#2044. 「CQOI2016」手机号码
题目描述
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少 333 个相邻的相同数字;号码中不能同时出现 888 和 444。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 111111 位数,前不含前导的 000。工具接收两个数 LLL 和 RRR,自动统计出 [L,R][L, R][L,R] 区间内所有满足条件的号码数量。LLL 和 RRR 也是 111111 位的手机号码。
输入格式
输入文件内容只有一行,为空格分隔的两个正整数 L,RL, RL,R。
输出格式
输出文件内容只有一行,为一个整数,表示满足条件的手机号数量。
样例
样例输入
12121284000 12121285550
样例输出
5
样例解释
满足条件的号码有:12121285000、 12121285111、 12121285222、 12121285333、 12121285550。
数据范围与提示
对于 30%30\%30% 的数据,R−L≤107R - L \leq 10^7R−L≤107;
对于 100%100\%100% 的数据,1010≤L≤R<101110^{10} \leq L \leq R < 10^{11}1010≤L≤R<1011。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int a[20]; long long l,r,f[20][10][10][2][2][2]; long long dfs(int pos,int p1,int p2,bool p3,bool p4,bool p8,bool limit) { if(p4&&p8) return 0; if(pos==0) {return p3;} if(!limit && f[pos][p1][p2][p3][p4][p8]!=-1)return f[pos][p1][p2][p3][p4][p8]; int End=9; if(limit)End=a[pos]; long long ans=0; for(int i=0;i<=End;i++) ans+=dfs(pos-1,p2,i,(p1==p2&&p2==i)||p3,(i==4)||p4,(i==8)||p8,limit&&(i==a[pos])); if(!limit)f[pos][p1][p2][p3][p4][p8]=ans; return ans; } long long solve(long long x) { int len=0; while(x){ len++; a[len]=x%10; x/=10LL; } long long res=0; for(int i=1;i<=a[len];i++) res+=dfs(len-1,0,i,0,i==4,i==8,i==a[len]); return res; } int main() { memset(f,-1,sizeof(f)); cin>>l>>r; if(l==10000000000) cout<<solve(r); else cout<<solve(r)-solve(l-1); return 0; }