P4124 [CQOI2016] 手机号码
//URL: /* 工具需要检测的号码特征有两个:号码中要出现至少 33 个相邻的相同数字;号码中不能同时出现 88 和 44。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。 手机号码一定是 1111 位数,前不含前导的 00。工具接收两个数 LL 和 RR,自动统计出 [L,R][L,R] 区间内所有满足条件的号码数量。LL 和 RR 也是 1111 位的手机号码 // pos 当前位置 // a 上一位数字 // b 再上一位数字 // state 是否出现3个连续相同数字 // eight 是否出现8 // four 是否出现4 f[pos][a][b][state][eight][four] 1 如何避开前导零 从头开始枚举 */ /* 12121284000 12121285550 5 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<string.h> #include<queue> #include<vector> #include<bits/stdc++.h> typedef long long ll; #define ddd printf("-----------------------\n"); using namespace std; const int maxn=1e1 +10; const int mod=998244353; const int inf=0x3f3f3f3f; int num[15]; ll L,R,f[13][10][10][2][2][2]; ll dfs(int pos,int a,int b,int sta,int et,int fr,int lim) { if(et&&fr) return 0; if(pos==0) return sta; if(lim==0&&f[pos][a][b][sta][et][fr]!=-1) return f[pos][a][b][sta][et][fr]; int end=lim? num[pos]:9; ll res=0; for(int i=0;i<=end;i++){ res+=dfs(pos-1,i,a,sta||(i==a&&i==b),et||i==8,fr||i==4,lim&&i==end); } if(lim==0) f[pos][a][b][sta][et][fr]=res; return res; } ll solve(ll x) { int len=0; memset(f,-1,sizeof(f)); while(x) { num[++len]=x%10; x/=10; } if(len!=11) return 0; ll ans=0; for(int i=1;i<=num[len];i++) ans+=dfs(len-1,i,0,0,i==8,i==4,i==num[len]); //ans=dfs(len,0,0,0,0,0,1); return ans; } int main() { ios::sync_with_stdio(false); cin>>L>>R; cout<<solve(R)-solve(L-1)<<'\n'; return 0; }