题目传送门:【HDU 2089】
题目大意:多组数据。求给定区间 [n,m] 中,不含数字串“4”或“62”的数的个数。(0 < n ≤ m < 1000000)
当输入为 n=m=0 时表示输入结束。
题目分析:
本人真正写的第一道数位 DP 题就是它了。
这道题应该是裸的数位 DP。题目中让你求区间中不含“4”或“62”的数的个数,如果我们用记忆化搜索的思想,那么在我们 DFS 的时候,参数里面还需要再记录下上一位数 prev 是多少。如果 prev=6,则接下来的一位就不能取 2。其余情况大致相同,没有太大变化。
For me:我还在 DFS 里加了一个参数 bit,表示我当前 DFS 到的这个数的总位数是多少。防止前导 0 影响最终答案。
下面附上代码:
- #include<cstdio>
- #include<cstring>
- #include<iostream>
- #include<algorithm>
- using namespace std;
- typedef long long LL;
- const int MX=10;
- int w[MX],f[MX][MX][10],ansa=0,ansb=0;
- //w:记录下每一位数是多少
- //f:总共 i 位数,当前选到第 j 位数,这一位数是 k 的总方案数
- int dfs(int bit,int dep,bool limit,bool lead,int prev){
- if (dep==0){
- if (!lead) return 1;
- return 0;
- }
- int lim=(limit==true ? w[dep] : 9) ,cnt=0,tot=0; //cnt:当前这一位取 i 时的方案数
- //tot:上一位数为 prev 时的总方案数
- for (int i=0;i<=lim;i++){
- if (i==4) continue;
- if (prev==6 && i==2) continue;
- if (!limit && !lead && i!=6 && f[bit][dep][i]!=-1){ //记忆化搜索,需要注意”62”,因此前缀为6时继续向下搜
- cnt=f[bit][dep][i];
- tot+=cnt;
- continue;
- }
- cnt=dfs(bit-(lead && i==0),dep-1,limit && i==lim,lead && i==0,i);
- if (f[bit][dep][i]==-1) f[bit][dep][i]=cnt;
- tot+=cnt;
- }
- return tot;
- }
- void _init(){
- memset(f,-1,sizeof(f));
- memset(w,0,sizeof(w));
- ansa=0,ansb=0;
- }
- int main(){
- int a,b;
- memset(f,-1,sizeof(f));
- while (scanf(“%d%d”,&a,&b)){
- if (a==0 && b==0) break;
- a–; //前缀和相减
- int wei=0; //wei:表示最高位
- while (b){
- w[++wei]=b%10;
- b/=10;
- }
- ansb=dfs(wei,wei,true,true,0);
- wei=0;memset(w,0,sizeof(w));
- while (a){
- w[++wei]=a%10;
- a/=10;
- }
- ansa=dfs(wei,wei,true,true,0);
- printf(”%d\n”,ansb-ansa);
- _init();
- }
- return 0;
- }