Luogu P4124 [CQOI2016]手机号码 题解

Describe

题目链接

人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。 工具需要检测的号码特征有两个:号码中要出现至少 $3$ 个相邻的相同数字;号码中不能同时出现 $8$ 和 $4$。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。 手机号码一定是 $11$ 位数,前不含前导的 $0$。工具接收两个数 $L$ 和 $R$,自动统计出 $[L,R]$ 区间内所有满足条件的号码数量。$L$ 和 $R$ 也是 $11$ 位的手机号码。

Solution

数位dp 注意细节

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[15],m,f[15][10][10][2][2][2][2][2];
inline int DFS(int x,int las,int lasqr,int has,int is4,int is8,int lim,int st){
if(is4&&is8) return 0;
if(x==0) return has;
if(~f[x][las][lasqr][has][is4][is8][lim][st]) return f[x][las][lasqr][has][is4][is8][lim][st];
int Max=lim?a[x]:9,res=0;
for(int i=0;i<=Max;i++)
if(st==1) res+=DFS(x-1,i,las,has,is4(i==4),is8(i==8),lim&&(i==Max),st&&(i==0));
else res+=DFS(x-1,i,las,has(las==lasqr&&las==i),is4(i==4),is8(i==8),lim&&(i==Max),st&&(i==0));
return f[x][las][lasqr][has][is4][is8][lim][st]=res;
}
inline int solve(int n){
m=0;memset(f,-1,sizeof(f));
while(n){
a[++m]=n%10;
n/=10;
}
return DFS(m,-1,-1,0,0,0,1,1);
}
int L,R;
signed main(){
scanf("%lld%lld",&L,&R);
printf("%lld\n",solve(R)-solve(L-1));
}