3820: 手机号码
题目描述
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少 3 个相邻的相同数字,号码中不能同时出现 8 和 4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 11 位数,前不含前导的 0。工具接收两个数 L 和 R,自动统计出 [L,R] 区间内所有满足条件的号码数量。L 和 R 也是 11 位的手机号码。
输入
有多行数据输入
每行为空格分隔的 2 个正整数 L, R。
输出
输出内容只有一行,为 1 个整数,表示满足条件的手机号数量。
样例输入
12121284000 12121285550
样例输出
5
提示
满足条件的号码:12121285000、12121285111、12121285222、12121285333、12121285550
对于 100% 的测试数据,10^10 ≤ L ≤ R < 10^11
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll dp[11][3][10][2][2],L,R;
int bit[30];
ll dfs(int pre,int len,int pos,bool is4,bool is8,bool isok){
if (pos<0) return (len>2&&!(is4&&is8));
if (is4&&is8) return 0;
if (isok&&dp[pos][len][pre][is4][is8]+1) return dp[pos][len][pre][is4][is8];
ll sum=0;
int l,mxn=(isok)?9:bit[pos];
for (int i=mxn;i>=0;--i){
if (len>=3) l=3;
else if (i==pre) l=len+1;
else l=1;
sum+=dfs(i,l,pos-1,is4||i==4,is8||i==8,isok||i<mxn);
}
if (isok) dp[pos][len][pre][is4][is8]=sum;
return sum;
}
ll solve(ll n) {
if (n <= 9999999999) return 0;
for (int i=0;i<11;++i)
bit[i]=n%10,n/=10;
ll sum = 0;
for (int i=1;i<=bit[10];++i)
sum+=dfs(i,1,9,i==4,i==8,i<bit[10]);
return sum;
}
int main() {
memset(dp,-1,sizeof dp);
while(~scanf("%lld%lld",&L,&R)) {
printf("%lld\n",solve(R)-solve(L-1));
}
return 0;
}