给定区间 [L,R] ,求区间内满足以下条件的数的个数
1.不能同时含有4,8
2.必须至少三位相邻位的数码相同
例如11125877157满足条件而11148521234,11010110110不满足。
题解在下面
这个一眼数位动规。用递推写我认为需要勇气……所以我是记搜的。
想想需要哪些属性?
因为当前位的状态肯定和是否出现4、8有关,所以我们设isF, isE来表示 是否出现4,是否出现8。
又因为我需要连续相同这个属性,所以我们可以想到维护p2, p1,分别表示当前位+2,当前位+1这两个数位上是什么数。
同时,因为可能之前满足了相等性质但是现在看不出来,所以我们加入Req表示是否满足相等性质。
这里我认为前导零可以加以处理。我用10表示前导0,规避了一些判断。
#include
#include
using namespace std;
typedef long long LL;
LL Dp[15][12][12][2][2][2],bit[15];
LL Solve1(LL A,LL B)
{ LL i,j,t,len,p2,p1,Ans=0;
bool isF,isE,Req,flag;
for(i=A;i<=B;i++)
{ t=i;len=0;
while(t>0){bit[++len]=(t%10LL);t/=10LL;}
p2=p1=10;Req=0;isF=isE=0;
for(j=len;j>=1;j--)
{ isF=isF||(bit[j]==4LL);
isE=isE||(bit[j]==8LL);
if(isF&&isE)break;
if(p2!=10&&p2==p1&&p1==bit[j])
Req=1;
p2=p1;p1=bit[j];
}
if(Req&&j==0)Ans++;//printf("%lld\n",i);}
}
return Ans;
}
LL DFS(int len,int p2,int p1,bool isF,bool isE,bool Req,bool flag)
{ if(isF&&isE)return 0;
if(!len)
{ if(Req)return 1;
return 0;
}
if(!flag&&Dp[len][p2][p1][isF][isE][Req]!=-1)
return Dp[len][p2][p1][isF][isE][Req];
int Max,Ni;bool nR;LL Tmp=0;
if(flag)Max=bit[len];else Max=9;
for(int i=0;i<=Max;i++)
{ if(p1==10&&i==0)Ni=10;else Ni=i;
nR=Req||(p2!=10&&p2==p1&&p1==i);
Tmp+=DFS(len-1,p1,Ni,isF||(i==4),isE||(i==8),nR,flag&&(i==Max));
}
if(!flag)Dp[len][p2][p1][isF][isE][Req]=Tmp;
return Tmp;
}
LL Solve2(LL x)
{ int len=0;
while(x>0){bit[++len]=(x%10LL);x/=10LL;}
return DFS(len,10,10,0,0,0,1);
}
int main(){
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
LL L,R;
memset(Dp,-1,sizeof(Dp));
scanf("%lld%lld",&L,&R);
if(R-L<=10000)printf("%lld\n",Solve1(L,R));
else printf("%lld\n",Solve2(R)-Solve2(L-1));
fclose(stdin);fclose(stdout);
return 0;
}