1. 程式人生 > >HDU 3555 數位DP 入門

HDU 3555 數位DP 入門

/**
*    數位dp:
*    和hdu 2089 類似,不過這個其實更簡單。
*   不過有一點不同的是,在計數的時候,因為要找的是子串“49”,
*   所以不需要考慮在if(num[i] > 9 && last == 4) 的情況
*   而hdu 2089的子串是“62”,也就是當在if(num[i] > 2 && last == 6)情況的時候
*   仍需考慮num[i] > 2,因為這裡還有個num[i]取2的數,所以要多加個 dp[i][1];
*     其次就是num[i] == 9的時候,這個一開始想了有點久,為什麼num[i]=9, num[i+1]=4
*   的時候不需要算呢? 也就是為什麼是if(num[i] > 9 && last == 6) 而不是 if(num[i] >= 9 && last == 6)
*   其實當num[i] = 9, num[i+1] = 4 的時候把flag設成true,也就是表示已經出現了以49xxx形式的數
*   其實這裡就已經算了49xxx了,就不用在當前步算49,而是在之後的flag為true的時候都是這種情況。
*/

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#define DEBUG 0
#define INF 0x1fffffff
#define MAXN 25


typedef long long LL;
using namespace std;

int num[MAXN];
LL dp[MAXN][3];  // 0-所有不存在  1-不存在以9開頭 2-存在

LL cal(LL x)
{
    int cnt = 1;
    while(x)
    {
        num[cnt++] = x % 10;
        x /= 10;
    }

    int last = 0, flag = 0;
    LL ans = 0;
    for(int i = cnt - 1; i > 0; i --)
    {
        ans += dp[i-1][2] * num[i];   // 0 - 4

        if(flag)
        {
            ans += dp[i-1][0] * num[i];
        }
        else
        {
            if(num[i] > 4) {
                ans += dp[i-1][1];
            }

        }
        if(last == 4 && num[i] == 9)
            flag = 1;
        last = num[i];
    }

    return ans;
}

int main()
{
    int t;

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

    cin >> t;
    while(t --)
    {
        LL x;
        cin >> x;
        cout << cal(x+1) << endl;
    }

    return 0;
}