BZOJ4521: [Cqoi2016]手机号码

Description

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不
吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号
码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数
量。
工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字,号码中不能同
时出现8和4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、
23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是11位数,前不含前导的0。工具接收两个数L和R,自动统计出[L,R]区间
内所有满足条件的号码数量。L和R也是11位的手机号码。

Input

输入文件内容只有一行,为空格分隔的2个正整数L,R。
10^10 < =  L < =  R < 10^11

Output

输出文件内容只有一行,为1个整数,表示满足条件的手机号数量。

Sample Input

12121284000 12121285550

Sample Output

5
样例解释
满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550

啊啊啊这么多天终于有一道不看题解做出来的题了
数位dp,考虑用记忆化搜索的方式实现...
状态的定义:
具体实现看代码吧,总算是从刚开始七零八落的思维一点点构建出来了
需要提醒的一点是,对于9999999999(十个9)来说,要强制转化成09999999999,即十一位数
因为这个dp是包含前导零的
前面多填一个0会多增加许多贡献(两个零连在前头)有57977624个(别问我怎么知道的(;´д`)ゞ
 
 
 1 #include<cstdio>
 2 #include<cstring>
 3 #define ll long long
 4 using namespace std;
 5 ll L,R;
 6 int a[20],tot;
 7 ll F[12][2][2][5][12][15];
 8 ll ksm(ll x,ll t){
 9     ll ans=1;
10     for(;t;t>>=1,x=(x*x))if(t&1)ans=(ans*x);
11     return ans;
12 }
13 ll dfs(int i,bool f,int t,int x,int k,int w){
14 //µÚiλ¼°ÒÔºó¶¼Ã»Ìf¸ü¸ßµÄλÊÇ·ñ¶¼½ôÌù×ÅR,ĩβÁ¬ÐøÊý×ÖÊýÁ¿ÊÇk
15 //tÊÇ·ñÒѾ­º¬ÓÐ3Á¬£¬x=-1 ÎÞ8ÎÞ4£¬x=0ÓÐ4ÎÞ8£¬x=1ÓÐ8ÎÞ4 
16 //wÉÏÒ»´ÎĩβÊý×ÖÊǼ¸ 
17     if(F[i][f][t][x+1][k][w+1]!=-1)return F[i][f][t][x+1][k][w+1];
18     ll ans=0;
19     if(i==0){
20         ans=t;
21     }
22     else if(f==0&&t==1){
23         if(x==0||x==1)ans=ksm(9,i);
24         else ans=ksm(9,i)*2-ksm(8,i);
25     }
26     else if(f==0){
27         for(int j=0;j<=9;j++){
28             if(j==4&&x!=1)
29                 ans+=dfs(i-1,f,t|((w==j?k+1:1)>=3),0,w==j?k+1:1,j);
30             else if(j==8&&x!=0)
31                 ans+=dfs(i-1,f,t|((w==j?k+1:1)>=3),1,w==j?k+1:1,j);
32             else if(j!=8&&j!=4)
33                 ans+=dfs(i-1,f,t|((w==j?k+1:1)>=3),x,w==j?k+1:1,j);
34         }
35     }
36     else{
37         for(int j=0;j<a[i];j++){
38             if(j==4&&x!=1)
39                 ans+=dfs(i-1,0,t|((w==j?k+1:1)>=3),0,w==j?k+1:1,j);
40             else if(j==8&&x!=0)
41                 ans+=dfs(i-1,0,t|((w==j?k+1:1)>=3),1,w==j?k+1:1,j);
42             else if(j!=8&&j!=4)
43                 ans+=dfs(i-1,0,t|((w==j?k+1:1)>=3),x,w==j?k+1:1,j);
44         }
45         if(a[i]==4&&x!=1)
46             ans+=dfs(i-1,f,t|((w==a[i]?k+1:1)>=3),0,w==a[i]?k+1:1,a[i]);
47         else if(a[i]==8&&x!=0)
48             ans+=dfs(i-1,f,t|((w==a[i]?k+1:1)>=3),1,w==a[i]?k+1:1,a[i]);
49         else if(a[i]!=8&&a[i]!=4)
50             ans+=dfs(i-1,f,t|((w==a[i]?k+1:1)>=3),x,w==a[i]?k+1:1,a[i]);
51     }
52     F[i][f][t][x+1][k][w+1]=ans;
53     return ans;
54 }
55 ll work(ll R){
56     memset(F,-1,sizeof(F));
57     tot=0;
58     while(R){
59         a[++tot]=R%10;
60         R/=10;
61     }
62     if(tot==10)a[11]=0;
63     return dfs(11,1,0,-1,0,-1);
64 }
65 int main(){
66     scanf("%lld%lld",&L,&R);
67     printf("%lld",work(R)-work(L-1));
68     return 0;
69 }
View Code

 

posted @ 2019-01-11 11:45  瞬闪影  阅读(178)  评论(0编辑  收藏  举报