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;    

}

你可能感兴趣的:(HDU)