[BZOJ4521][Cqoi2016]手机号码 (数位dp)

题目描述

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。

工具需要检测的号码特征有两个:号码中要出现至少 33 个相邻的相同数字;号码中不能同时出现 88 和 44 。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。

手机号码一定是 11 位数,前不含前导的 00 。工具接收两个数 LL 和 RR ,自动统计出 [L,R][L,R] 区间内所有满足条件的号码数量。 LL 和 RR 也是 1111 位的手机号码。

输入输出格式

输入格式:

 

输入文件内容只有一行,为空格分隔的 22 个正整数 L,RL,R 。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
12121284000 12121285550
输出样例#1: 复制
5

说明

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

数据范围: 10^{10}\leq L\leq R<10^{11}1010LR<1011 。

题解

  什么鬼?用scanf就会错?要用cin才行?

  一道数位dp,我就直接记忆化搜索了

  因为是十一位数,所以限制一下第一位不能为0

  然后剩下的东西还是看代码好了

 1 //minamoto
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<iostream>
 5 #define ll long long
 6 using namespace std;
 7 ll dp[12][12][2][2][4],a,b;
 8 int num[12],len;
 9 ll dfs(int pos,int Pre,int m1,int m2,int cov,bool flag){
10     if(m1&&m2) return 0;
11     if(!pos) return cov==3;
12     if(!flag&&(~dp[pos][Pre][m1][m2][cov])) return dp[pos][Pre][m1][m2][cov];
13     ll res=0;int lim=flag?num[pos]:9;
14     for(int i=pos==len;i<=lim;++i){
15         switch(cov){
16             case 0:res+=dfs(pos-1,i,m1|(i==4),m2|(i==8),1,flag&&(i==lim));break;
17             case 3:res+=dfs(pos-1,i,m1|(i==4),m2|(i==8),3,flag&&(i==lim));break;
18             default:res+=dfs(pos-1,i,m1|(i==4),m2|(i==8),i==Pre?cov+1:1,flag&&(i==lim));break;
19         }
20     }
21     if(!flag) dp[pos][Pre][m1][m2][cov]=res;
22     return res;
23 }
24 ll solve(ll x){
25     len=0;
26     for(;x;x/=10) num[++len]=x%10;
27     return dfs(len,0,0,0,0,1);
28 }
29 int main(){
30     memset(dp,-1,sizeof(dp));
31     ios::sync_with_stdio(false);
32     cin>>a>>b;
33     cout<<(a==10000000000?solve(b):solve(b)-solve(a-1))<<endl;
34     return 0;
35 }

 

posted @ 2018-08-27 10:12  bztMinamoto  阅读(200)  评论(0编辑  收藏  举报
Live2D