题目描述
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少 3 个相邻的相同数字;号码中不能同时出现 8 和 4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 11 位数,前不含前导的 0。工具接收两个数 L 和 R,自动统计出 [L,R] 区间内所有满足条件的号码数量。L 和 R也是 11 位的手机号码。
输入格式
输入文件内容只有一行,为空格分隔的 2 个正整数 L,R。
输出格式
输出文件内容只有一行,为 1 个整数,表示满足条件的手机号数量。
输入输出样例
输入 #1
12121284000 12121285550
输出 #1
5
说明/提示
样例解释:满足条件的号码: 12121285000、 12121285111、 12121285222、 12121285333、 12121285550。
数据范围:
10^10 <= L,R <= 10^11
思路:
这是一道 数位DP
代码:
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> #include"cstring" using namespace std; #define int long long int l,r,len,num[15],dp[13][13][13][2][2][2][2]; int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int f(int p,int a,int b,bool c,bool d,bool pan4,bool pan8) { if(pan4 && pan8)return 0; if(p <= 0)return c; int res=0; int lim= !d ? num[p] : 9; if( dp[p][a][b][c][d][pan4][pan8] !=-1) return dp[p][a][b][c][d][pan4][pan8]; for(int i=0;i<=lim;i++) { res+=f( p-1 , i , a , c||(i==b&&i==a) , d||(i<lim) ,pan4||(i==4),pan8||(i==8)); } return dp[p][a][b][c][d][pan4][pan8] = res; } int calc(int x) { if(x < 1e10)return 0; memset(dp ,-1 , sizeof( dp ) ); for(len=0 ; x; x/=10) num[++len] = x%10; int res = 0; for ( int i = 1;i <= num[len]; i++) { res+=f(10,i,0,0,i<num[len],i==4,i==8); } return res; } signed main() { l = read(); r = read(); printf("%lld", calc(r) - calc(l-1) ); return 0; }