re:从零开始的数位dp

起源:唔,,前几天打cf,edu50那场被C题虐了,决定学学数位dp,此文持续更新,9.16号之前会更新完的。

ps:我也什么都不会遇到一些胡话大家不要喷我啊。。。

数位dp问题:就是求在区间l到r上满足规定条件的数的个数。

ex1:hdu3555

  题意:给你n,求从一到n中有多少个数不包含“49”。(t<=1e4,n<=2^63-1)

  首先数位dp顾名思义就是对数位进行dp嘛,所以dp数组的第一维我们用来保存数字的位数,第二位我们用来判定当前位是否为4,

所以就是  dp[20][2];  这个样子。 在这之前我们先考虑一下常规的搜索思路,一件非常显然的事情,在[1,1000]和[1001,2000]以及所有类似区间里符合要求的数都是一样的,这样我们就可以通过记忆化的方式来保存某些结果。

先给出solve函数

1 ll solve(ll num){
2     int k = 0;//记录数位
3     while(num){
4         k++;
5         digit[k]=num%10;
6         num/=10;
7     }
8     return dfs(k,false,true);
9 }
View Code

这个很好理解嘛,保存这个数各位上的数字。然后我们就可以进行记忆化搜索了,

dp[20][2]:表示 1.有4的时候有几个含有49, 2.没有4的时候,有几个含有49。

ll dfs(int len,bool if4,bool limit){
//当前是第几位,上一位是否是4,上一位是否是上界
if(len==0)//统计完了直接返回1
return 1;
if(!limit&&dp[len][if4])//不是上界并且这种情况已经统计过
return dp[len][if4];
ll cnt=0,up_bound=(limit?digit[len]:9);//up_bound是当前位能满足的最大值,如果上一位是上界的话,当前位最大只能取到当前位的数字,如果不是,当前位可以从0取到9
for(int i=0;i<=up_bound;i++){
if(if4&&i==9)
continue;//上一位是4并且这一位是9,GG了啊
cnt+=dfs(len-1,i==4,limit&&i==up_bound);//上一位是上界的情况下我们才会考虑这一位是否是上界
}
if(!limit)//不是上界,属于通用的情况,我们进行赋值
dp[len][if4]=cnt;
return cnt;
}
最后结果差分一下就好。

猜你喜欢

转载自www.cnblogs.com/MXang/p/9629526.html