HDU - 3555 Bomb(数位dp)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3555

题解:

开一个dp数组,i代表当前数字的长度,dp[i][0]表示不含49的数字个数,dp[i][1]表示最高位为9且不含49的数字的个数,dp[i][2]表示满足条件的数字个数。可以推出以下的递推公式:

dp[0][0] = 1;
for(int i = 1; i <= 22; i++)
{
    dp[i][0] = dp[i-1][0] * 10 - dp[i-1][1];//不含49的数字个数
    dp[i][1] = dp[i-1][0];//不含49 && 最高位为9的数字个数
    dp[i][2] = dp[i-1][1] + dp[i-1][2] * 10;//满足条件的数字个数
}

然后讲数字按位输入到数组里,flag代表高位有没有出现过49。首先加上a[i] * i-1位中满足条件的数的个数,如果高位出现过49,加上a[i] * i-1位中不满足条件的数的个数,如果高位没有出现过49, 且第i位 > 4,则加上剩下i-1位中以9开头的数的个数。最后判断高一位和本位是否构成49,更新flag。
注意这种处理需要将n+1,因为处理的是【1, n)的情况,并且需要将最高位的高一位位数表示为0。

AC代码:

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

long long int N;
int number[30];
long long int dp[25][3];

int main()
{
    dp[0][0] = 1;
    for(int i = 1; i <= 22; i++)
    {
        dp[i][0] = dp[i-1][0] * 10 - dp[i-1][1];//不含49的数字个数
        dp[i][1] = dp[i-1][0];//不含49 && 最高位为9的数字个数
        dp[i][2] = dp[i-1][1] + dp[i-1][2] * 10;//满足条件的数字个数
    }
    int T;
    scanf("%d", &T);
    while(T--)
    {
        cin >> N;
        N++;//将N加一
        bool flag = false;
        long long int ans = 0;
        int len = 0;
        memset(number,0,sizeof(number));
        while(N != 0)
        {
            number[++ len ] = N%10;
            N /= 10;
        }
        number[len + 1] = 0;//将高一位表示为0
        for(int i = len; i > 0; i--)
        {
            ans += number[i] * dp[i-1][2];
            if(flag)
                ans += dp[i-1][0] * number[i];
            if(number[i] > 4 && !flag)
                ans += dp[i-1][1];
            if(number[i+1] == 4 && number[i] == 9)
                flag = true;
        }
        cout << ans <<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值