HDU 3555: Bomb (数位DP)

类型:

数位DP

题意:求1~N内,含有49这个子串的数的个数。N<2^63-1

思路:基础数位DP。第一次做。

dp[i][d] 表示d开头的i位数中,不含49子串的个数

dp[i][d] = ∑dp[i-1][k] (0<=k<=9 && !(d==4 && k==9))

 

之后求0~N之间不包含49这个子串个数的做法是:

从最高位开始比较,ans += ∑dp[本位][0 ~ (N在本位的数 - 1)]

然后判断,如果本位如果取这个数,是否破坏规则(即包含49),如果是,跳出。

最后,如果N这个数本身不破坏规则,ans++。(算上本身)

最后的答案就是(N+1)-ans    // 加1是因为爱,,不,是因为0.

 

坑点:杭电 I64d .. 做题少啊~~~

代码:

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

long long dp[100][10];

int num[30];

void init() {
    for (int i = 0; i < 10; i++) {
        dp[1][i] = 1;
    }
    for (int i = 2; i <= 50; i++) {
        for (int d = 0; d < 10; d++) {
            dp[i][d] = 0;
            for (int k = 0; k < 10; k++) {
                if (d == 4 && k == 9) continue;
                dp[i][d] += dp[i-1][k];
            }
        }
    }
}

int main() {
    int t;
    scanf("%d", &t);

    init();

    while (t--) {
        long long N;
        cin>>N;

        long long ans = 0;
        long long tmp = N;
        int len = 0;
        while (tmp) {
            num[++len] = tmp%10;
            tmp/=10;
        }

        bool ok = true;
        for (int j = 0; j <= num[len]-1; j++) {
            ans += dp[len][j];
        }
        for (int i = len-1; i >= 1; i--) {
            for (int j = 0; j <= num[i]-1; j++) {
                ans += dp[i][j];
            }
            if (num[i+1] == 4 && num[i] == 9) {
                ok = false;
                break;
            }
        }
        if (ok) ans++;
        cout<<N+1-ans<<endl;
    }
    return 0;
}

 

posted on 2014-03-10 16:42  ShineCheng  阅读(184)  评论(0编辑  收藏  举报

导航