[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
 2 #include
 3 #include
 4 #include
 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(k1,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;k11,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;k11,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)
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;jif((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 }
View Code

 

转载于:https://www.cnblogs.com/czllgzmzl/p/5382505.html

你可能感兴趣的:([bzoj4521] [Cqoi2016]手机号码)