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
样例解释
满足条件的号码: 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 }