HDU2089 不要62

来源:互联网 发布:ping测试网络 编辑:程序博客网 时间:2024/04/27 18:49

中文题意自然不用赘述,原题请戳

解题思路

做的第一道数位DP的题,果然数位DP里面的各种思想都是我曾经没有怎么接触过的。
首先我们将状态分为三种
dp[i][0]:表示从0到长度为i的数的区间里面不包含不吉利的数,且末位不是6的数的个数
dp[i][1]:表示从0到长度为i的数的区间里面不包含不吉利的数,且末位是6的数的个数
dp[i][2]:表示从0到长度为i的数的区间里面不吉利的数的个数。
这样的话我们很容易就能将dp数组预处理出来
dp[i][0]是由前i-1位里面所有的吉利数加上一个不是4的数,还要减去在6后面加上一个2的情况,所以dp[i][0]=dp[i-1][0]*9-dp[i][1]。
dp[i][1]是由前i-1位里面所有的吉利数加上一个6得到;
dp[i][2]是由前i-1位里面所有的不吉利数,加上前i-1位里面所有吉利数加上一个4,以及末位为6的数后面加上一个2得到。
然后这样dp数组我们就预处理出来了,但是现在怎么算从0到一个数x里面有多少个不吉利数呢?
首先对于x,我们将它的每一位分离出来,对于第i位暂且称其为si,对于这一位我们能得到的不吉利数的个数,首先是比它低的位数里面所有数里面的不吉利数乘以si,比如si=5,那么就应该是dp[i-1][2]×5,其实这样我们得到的就已经是0到50000(暂且算这么大吧)里面所有的不吉利数。然后如果这个si比4大,那么必然有比它位数低的所有的数加上一个4所构成的不吉利数,如果这个si大于6的话,同理。那么如果下一位是2,然后si比6大的话,那么就必然出现了62相连。如果此时此刻遍历过的数位里面已经满足了不吉利数的诸多性质,那么剩下的数位不管是什么,就都是不吉利数了。
第一次做数位DP,感觉这个比较新的思想做起来还是挺happy的。

AC代码

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int dp[10][3], a, b;void init(){    memset(dp, 0, sizeof(dp));    dp[0][0] = 1;    for (int i = 1; i <= 8; i++){        dp[i][0] = dp[i-1][0] * 9 - dp[i-1][1];        dp[i][1] = dp[i-1][0];        dp[i][2] = dp[i-1][2]*10 + dp[i-1][1] + dp[i-1][0];    }}int DP(int x){    bool flag = 0;    int s[15];    int idx = 0, sum = x, ans = 0;    for (; x; x /= 10)        s[++idx] = (x%10);    s[idx+1] = 0;    for (int i = idx; i > 0; i--){        ans += (dp[i-1][2]*s[i]);        if (flag) ans += (dp[i-1][0]*s[i]);        else{            if (s[i] > 4) ans += dp[i-1][0];            if (s[i] > 6) ans += dp[i-1][1];            if (s[i+1] == 6 && s[i] > 2) ans += dp[i][1];        }        if (s[i] == 4 || s[i+1] == 6 && s[i] == 2) flag = 1;    }    return sum-ans;}int main(){    init();    while(scanf("%d%d", &a, &b) == 2 && (a+b))        printf("%d\n", DP(b+1) - DP(a));    return 0;}

0 0
原创粉丝点击