其实数位DP就是优化计数的过程。
如果事事用爆破的话就太有病了!!!除非我吃拧了!!!小学生都不会干的傻事!!!
其实数位dp就是dfs+记忆化数组
题目会给一个上界或者下界
然后让你统计范围内符合要求的数量!!!
解题步骤:
1.处理数位函数 cal() solve() ...自己命名 > 将输入的数进行分解
2.dfs的函数 => 执行的是数位dp(dfs+记忆化搜索)
例题体面:简单而言就是一个区间内含 49 的数有多少!!!
BombTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 23481 Accepted Submission(s): 8845 Problem Description The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point. Input The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description. Output For each test case, output an integer indicating the final points of the power. Sample Input 3 1 50 500 Sample Output 0 1 15Hint From 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499", so the answer is 15. |
#include<iostream>
using namespace std;
typedef long long LL;
int digit[20];//数位
LL dp[20][2];//当前数位 含有4时,区间内有多少数 没有49 当前数位不是4时 区间内有多少数 没有49 !!!
LL dfs(int len,bool if4,bool limit){
//len表示当前位 !! if4表示len的上一位是否是4 !! limit表示当前位的最大约束 !!
if(len==0) return 1; //个位数时 满足条件的个数仅为一!
if(!limit && dp[len][if4]) return dp[len][if4];
//当前数位的数 没有到达上界,且统计过 则直接返回!!
//典型的记忆化 的语句!!
LL cnt=0;
LL up_bound=(limit?digit[len]:9);//当前位 上界的约束!!
for(int i=0;i<=up_bound;++i){
if(if4 && i==9) // 上一位是4 且 这一位是9 这直接跳过 !!
continue; //剪枝 !
cnt+=dfs(len-1,(i==4)?1:0,/*为下一位设上限 !!*/limit&&i==up_bound);
}
if(!limit) dp[len][if4]=cnt;
//如果这一位 不含上界则作为完整的数 可以记录下来 !!
//统计在数位上 下次dfs时以便遇见直接返回!!
return cnt;
}
LL solve(LL num){
int k=0;
while(num){//数位的分解
digit[++k]=num%10;
num/=10;
}
return dfs(k,false,true);//dfs记忆爆搜
}
int main(){
int T;
LL N;
cin>>T;
while(T--){
cin>>N;
//N+1 是因为 有前导0 但前导0是不需要计入其中的 !!
cout<<N+1-solve(N)<<endl;
}
return 0;
}
///HDU 2089
不要62Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 58083 Accepted Submission(s): 22807 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。 Input 输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。 Output 对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。 Sample Input 1 100 0 0 Sample Output 80 |
题意:不要62和4
///HDU 2089
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int digit[20];
LL dp[20][2];
///if4=>status(状态)是否是6
LL dfs(int len,bool if6,bool limit){
if(len==0) return 1ll;
if(!limit && dp[len][if6]) return dp[len][if6];
LL cnt=0,up_bound=(limit?digit[len]:9);
for(int i=0;i<=up_bound;++i){
if(if6 && i==2)///=>找到一个49
continue;
if(i==4) continue;//剪枝
cnt+=dfs(len-1,i==6,limit&&i==up_bound);
}
if(!limit) dp[len][if6]=cnt;
return cnt;
}
///统计的是没有62的个数
LL solve(LL num){
int k=0;
while(num){
digit[++k]=num%10;
num/=10;
}
return dfs(k,false,true);
}
int main(){
LL N,M;
while(cin>>N>>M && N+M){
//注意0 0 的特判 当n=0时,n-1=-1,这时solve(-1)代入跑dfs,得出的结果就还真是0
//所以我感觉这套板子的强度很大!!! 满足卡特判的活!!!
//精髓在 !!!卡特判!!!
cout<<solve(M)-solve(N-1)<<endl;
}
return 0;
}