[CQOI2016] 手机号码 (数位dp)
$solution:$
$10^{10} \leq L \leq R < 10^{11}$这个数据范围很容易想到数位$dp$。
依照题意模拟即可。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define int long long using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } int l,r,dig[18],f[12][11][2][5][2][2]; int dfs(int pos,int las,bool done,bool pd,int now,bool pd4,bool pd8){ //cout<<"pos:"<<pos<<" las:"<<las<<" done:"<<done<<" pd:"<<pd<<" now:"<<now<<endl; //printf("pos:%d las:%d done:%d pd:%d now:%d\n",pos,las,done,pd,now); //system("pause"); if(pd4==1&&pd8==1) return 0; if(pos==0){ if(pd==1) return 1; return 0; } if(done==0) if(f[pos][las][pd][now][pd4][pd8]!=-1) return f[pos][las][pd][now][pd4][pd8]; int begin,end; if(las==11) begin=1; else begin=0; if(done==1) end=dig[pos];else end=9; int ans=0; for(int i=begin;i<=end;i++){ if(las==i){ if(now>=2) ans+=dfs(pos-1,i,done&&(i==dig[pos]),1,3,pd4|(i==4),pd8|(i==8)); else ans+=dfs(pos-1,i,done&&(i==dig[pos]),pd,now+1,pd4|(i==4),pd8|(i==8)); }else ans+=dfs(pos-1,i,done&&(i==dig[pos]),pd,1,pd4|(i==4),pd8|(i==8)); } if(done==0) f[pos][las][pd][now][pd4][pd8]=ans; return ans; }int Dig; int solve(int x){ dig[0]=0; while(x!=0){ dig[++dig[0]]=x%10; x/=10; } if(dig[0]!=Dig) return 0; return dfs(dig[0],11,1,0,0,0,0); } int Qdig(int x){ dig[0]=0; while(x!=0){ dig[++dig[0]]=x%10; x/=10; }return dig[0]; } signed main(){ memset(f,-1,sizeof(f)); l=read(),r=read();Dig=Qdig(r); printf("%lld\n",solve(r)-solve(l-1)); return 0; }