[bzoj4521] [Cqoi2016]手机号码
数位DP。。。。感人肺腑
f[i][j][k][l][0..1][0..1]表示i位的数字,开头数字是j,开头有连续k个j,整段数字里有l个连续数字,有无4,有无8。。。。
预处理sxbk= =。。感觉这题用递推反而比较好写。。从已知状态往外推比较好想(然而码长就gg了。(然而记忆化搜索调了半天。。
合并答案的时候反而简单些。。记录一下是否已有4,8,是否已有三个连续的数。
一开始以为l和r也是特殊手机号码结果WA了半天
喜闻乐见的垫底= =
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define ll long long 6 #define sh short 7 using namespace std; 8 ll f[12][10][12][12][2][2]; 9 bool u[12][10][12][12][2][2]; 10 int i,j,k,n,m; 11 ll l,r; 12 13 inline ll dfs(sh i,sh j,sh k,sh l,sh m,sh n){ 14 if(u[i][j][k][l][m][n])return f[i][j][k][l][m][n]; 15 16 if(k>l||k>i||l>i||(m&&n)||(j==4&&!m)||(j==8&&!n)||!k||!l){u[i][j][k][l][m][n]=1;return 0;} 17 18 u[i][j][k][l][m][n]=1;ll tmp=0; 19 if(k>1){ 20 if(k<l)tmp=dfs(i-k+1,j,1,l,m,n); 21 else for(sh l1=l;l1;l1--)tmp+=dfs(i-k+1,j,1,l1,m,n); 22 }else{ 23 for(sh j1=0;j1<10;j1++)if(j1!=j&&(j1!=4||m)&&(j1!=8||n)) 24 for(sh k1=1;k1<i;k1++)tmp+=dfs(i-1,j1,k1,l,m,n); 25 if(j==4||j==8) 26 for(sh j1=0;j1<10;j1++)if(j1!=4&&j1!=8) 27 for(sh k1=1;k1<i;k1++)tmp+=dfs(i-1,j1,k1,l,0,0); 28 } 29 // if(l==1)printf(" %d %d %d %d %d %d %lld\n",i,j,k,l,m,n,tmp); 30 return f[i][j][k][l][m][n]=tmp; 31 } 32 int s[233],top,num[10],last; 33 inline ll query(ll x){ 34 ll tmp,ans=0;register int i,j,k,l;bool f4=0,f8=0,f=0; 35 for(s[top=1]=x%10,tmp=x/10;tmp;tmp/=10)s[++top]=tmp%10; 36 if(top<11)return 0; 37 for(i=1;i<s[top];i++) 38 for(j=1;j<=11;j++)for(k=3;k<=11;k++)ans+=dfs(11,i,j,k,0,0)+dfs(11,i,j,k,0,1)+dfs(11,i,j,k,1,0); 39 if(top==12){ 40 for(j=1;j<10;j++)for(k=1;k<=11;k++)for(l=1;l<=11;l++)ans+=dfs(11,j,k,l,0,0)+dfs(11,j,k,l,0,1)+dfs(11,j,k,l,1,0); 41 return ans; 42 } 43 num[last=s[top]]=1;f4=s[top]==4,f8=s[top]==8; 44 for(i=top-1;i&&!(f4&&f8);i--){ 45 for(j=0;j<s[i];j++)if((j!=4||!f8)&&(j!=8||!f4)){ 46 if(j!=last)for(k=1;k<=i;k++)for(l=!f?3:1;l<=i;l++){ 47 ans+=dfs(i,j,k,l,0,0); 48 if(!f8)ans+=dfs(i,j,k,l,1,0); 49 if(!f4)ans+=dfs(i,j,k,l,0,1); 50 } 51 else for(k=1;k<=i;k++)for(l=1;l<=i;l++)if(k+num[last]>=3||l>=3||f){ 52 ans+=dfs(i,j,k,l,0,0); 53 if(!f8)ans+=dfs(i,j,k,l,1,0); 54 if(!f4)ans+=dfs(i,j,k,l,0,1); 55 } 56 } 57 if(last==s[i])num[last]++;else num[last]=0,num[last=s[i]]=1; 58 f4|=s[i]==4,f8|=s[i]==8; 59 if(num[last]>=3)f=1; 60 } 61 return ans; 62 } 63 int main(){ 64 for(i=0;i<10;i++)f[1][i][1][1][i==4][i==8]=1; 65 memset(u[1],1,sizeof(u[1])); 66 // printf("%lld\n",dfs(5,8,1,2,0,1)); 67 scanf("%lld%lld",&l,&r); 68 printf("%lld\n",query(r)-query(l)+1); 69 return 0; 70 }