动态规划学习系列——数位DP(练手一)

来源:互联网 发布:工商银行网络银行 编辑:程序博客网 时间:2024/04/30 17:42

大概了解了什么是数位DP,想做几道题练练手,于是找到了这道题:
题目链接:hdu 2089 不要62
题目大意是统计【A,B】区间内没有4并且没有62的数,因为有之前那道题的铺垫,很快想到了解决方法。
思路: 预处理一个dp数组,dp【i,j】代表最高位为 j 的 i 位数满足题述要求的的个数;然后分别统计【0,B】和【0,A-1】区间内满足条件的数——与之前那题类似,不过更简单了,具体来看代码吧:
代码

#include <cstdio>using namespace std;int n,m,dp[10][10],num[10],cnt,ans;int solve(int n){    cnt=0,ans=0;    while(n){                 //处理出n的每一位        num[++cnt]=n%10;        n/=10;    }    num[cnt+1]=0;    for(int k=cnt;k>=1;k--)    {        for(int i=0;i<num[k];i++)        {            if(i!=4&&!(num[k+1]==6&&i==2))                ans+=dp[k][i];        }        if(num[k]==4||(num[k+1]==6&&num[k]==2))            break;    }    return ans;}int main(){    dp[0][0]=1;    for(int i=1;i<=9;i++)        for(int j=0;j<=9;j++)            for(int k=0;k<=9;k++)                if(j!=4&&!(j==6&&k==2))                    dp[i][j]+=dp[i-1][k];    while(scanf("%d %d",&n,&m)&&n&&m)    {        printf("%d\n",solve(m+1)-solve(n));    }    return 0;}

从代码看,我们求解【0,B】区间内符合条件的数的方法依旧类似,从最高位(k = cnt)开始,每次取一位,统计最高位为 i 的数的个数(0 <= i <= num[k]),于是变成下面的代码:

for(int k=cnt;k>=1;k--){    for(int i=0;i<num[k];i++)    {        if(i!=4&&!(num[k+1]==6&&i==2))            ans+=dp[k][i];    }    if(num[k]==4||(num[k+1]==6&&num[k]==2))        break;}

这里有一个需要注意的地方:如果之前的的数位已经出现不符合的情况了,那么我们就不应该继续统计下去!(因为这个WA了一次)

总结
理解过上一道数位DP之后,看这道题并不会那么吃力了,其实两道题本质上是差不多的,只是最后进行数位统计的部分有点不同(难怪当时TA说砍树那题是经典题)。

0 0