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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值