题目描述
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数量。
工具需要检测的号码特征有两个:号码中要出现至少 33 个相邻的相同数字;号码中不能同时出现 88 和 44。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。
手机号码一定是 1111 位数,前不含前导的 00。工具接收两个数 LL 和 RR,自动统计出 [L,R][L,R] 区间内所有满足条件的号码数量。LL 和 RR 也是 1111 位的手机号码。
输入格式
输入文件内容只有一行,为空格分隔的 22 个正整数 L,RL,R。
输出格式
输出文件内容只有一行,为 11 个整数,表示满足条件的手机号数量。
1.预处理 1.1输入 1.2清零数组 1.3拆位 1.4开始搜索 2.计算符合条件的数字个数 2.1返回不可以的状态 2.2返回只有一位的情况 2.3返回已经计算出结果的情况(也就是记忆化) 2.4循环 2.4.1把所有不符合的状态全部continue掉 2.4.2分类dfs下一个情况 2.4返回答案以及结束本函数 3.输出
#include<bits/stdc++.h> #define int long long//个数可能超过int范围 using namespace std; int num[15],dp[15][15][15][2][2][2][2];//当前位数,前一位,前两位,之前是否已经出现连续三个相同的数字,之前是否已经保证x<n,4,8 int dfs(int p,int a,int b,int c,int d,int _4,int _8) { if(_4==1&&_8==1) return 0;//先判断不可能的情况再判断可以的情况 if(p==0) return c; if(dp[p][a][b][c][d][_4][_8]!=-1) return dp[p][a][b][c][d][_4][_8]; int m=d?9:num[p],ans=0; for(int i=0;i<=m;i++) { if(i==4&&_8==1) continue; if(i==8&&_4==1) continue; ans+=dfs(p-1,i,a,c||(i==b&&b==a),d||(i<m),_4||(i==4),_8||(i==8)); } return dp[p][a][b][c][d][_4][_8]=ans; } int work(int x) { if(x<10000000000) return 0; int len=0,rst=0; memset(num,0,sizeof(num)); memset(dp,-1,sizeof(dp)); for(;x;x/=10) { num[++len]=x%10; } for(int i=1;i<=num[len];i++) { rst+=dfs(10,i,0,0,i<num[len],i==4,i==8); } return rst; } signed main() { int l,r; cin>>l>>r; if(l>r)//特判 { printf("0"); return 0; } cout<<work(r)-work(l-1);//注意边界要考虑进去 return 0; }
原文:https://www.cnblogs.com/decadent-slay/p/11566082.html