HDU-3555 Bomb 数位DP

这题的状态真的是很难想到,网上的代码都惊人的相似...

另一种解法,相比而言好接受一点:

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef unsigned long long Int64;

Int64 dp[20][3], N;

int digit[20];

Int64 dfs(int pos, int statu, int limit)
{
    if (pos == -1) { // 如果到了已经枚举了最后一位,并且在枚举的过程中有49序列出现 
        return statu == 2;
    }
    if (!limit && dp[pos][statu] != -1) return dp[pos][statu];  // 对于有限制的询问我们是不能够记忆化的 
    Int64 sum = 0;
    int s, end = limit ? digit[pos] : 9; // 确定这一位的上限是多少 
    for (int i = 0; i <= end; ++i) { // 每一位有这么多的选择 
        s = statu; // 有点else s = statu 的意思 
        if (statu == 1 && i == 9) s = 2;
        if (statu == 0 && i == 4) s = 1;
        if (statu == 1 && i != 4 && i != 9) s = 0;
        sum += dfs(pos-1, s, limit && i == end);
    }
    if (!limit) dp[pos][statu] = sum;
    return sum;
}

Int64 Cal(Int64 x)
{
    int len = -1;
    while (x != 0) {
        digit[++len] = x % 10;
        x /= 10;
    }
    return dfs(len, 0, 1);
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--) {
        memset(dp, 0xff, sizeof (dp));
        scanf("%I64u", &N);
        printf("%I64u\n", Cal(N));
    }
    return 0;    
}

 

详见代码:

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef unsigned long long int Int64;

Int64 N, dp[25][3];

int digit[25];

/*
dp[len][0] 表示前len位没有49的数字的个数
dp[len][1] 表示前len位没有49但是以9结尾的数的个数
dp[len][2] 表示前len位有49的状态 
*/

void pre()
{
    dp[0][0] = 1;
    for (int i = 1; i <= 20; ++i) {
        dp[i][0] = 10 * dp[i-1][0] - dp[i-1][1];
        dp[i][1] = dp[i-1][0];
        dp[i][2] = 10 * dp[i-1][2] + dp[i-1][1];
    }
}

int main()
{
    pre();
    int T, len, flag;
    Int64 ret;
    scanf("%d", &T);
    while (T--) {
        flag = ret = 0;
        scanf("%I64u", &N);
        ++N;
        memset(digit, 0, sizeof (digit));
        for (len = 1; N; ++len) {
            digit[len] = N % 10;
            N /= 10;
        }
        for (int i = len-1; i >= 1; --i) {
            ret += digit[i] * dp[i-1][2]; // 已经有49就直接加上 
            if (flag) {
                ret += digit[i] * dp[i-1][0];
            }
            else if (!flag && digit[i] > 4) {
                ret += dp[i-1][1];    
            }
            if (digit[i+1] == 4 && digit[i] == 9) {
                flag = 1;
            }
        }
        printf("%I64u\n", ret);
    }
    return 0;    
}
posted @ 2012-08-13 01:31  沐阳  阅读(473)  评论(2编辑  收藏  举报