hdu 3555 Bomb【数位dp~吖!!!!!】

Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 12675    Accepted Submission(s): 4525


Problem Description
The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point.
Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?
 

Input
The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.

The input terminates by end of file marker.
 

Output
For each test case, output an integer indicating the final points of the power.
 
Sample Input
3
1
50
500
 


Sample Output
0
1
15



Author
fatboy_cw@WHU
 
题目大意:
给你一个数据n,让你求出(0-n]之间包含49的数据个数。
思路:求不包含49的数据个数,然后再用n-这个个数即可,处理方法:数位dp、
我们设dp【i】【j】表示长度为i的,第i位上数据为j的个数,然后一点一点一点一点一点一点慢慢加起来。
预处理dp【i】【j】:
void init()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=21;i++)//枚举长度
    {
        for(int j=0;j<10;j++)//枚举第i位上的数据
        {
            for(int k=0;k<10;k++)//枚举第i-1位上的数据。
            {
                if(!(j==4&&k==9))//合法的情况下累加
                {
                    dp[i][j]+=dp[i-1][k];//长度为i,数据为j的情况数。
                }
            }
        }
    }
}
AC代码:
这里因为solve()函数求的是(0-n)的数据,所以在处理的时候n要+1,因为long long 的数据是到2^63-1的,所以我们避免2^63会出现不对的数据,我们开llu。

#include<stdio.h>
#include<string.h>
using namespace std;
#define ll unsigned long long
ll dp[25][10];
ll digit[25];
void init()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=21;i++)
    {
        for(int j=0;j<10;j++)
        {
            for(int k=0;k<10;k++)
            {
                if(!(j==4&&k==9))
                {
                    dp[i][j]+=dp[i-1][k];//长度为i,最后数字为j的情况数。
                }
            }
        }
    }
}
ll calchangdu(ll n)
{
    ll cont=0;
    while(n)
    {
        cont++;
        n/=10;
    }
    return cont;
}
ll caldigit(ll n,ll len)
{
    memset(digit,0,sizeof(digit));
    for(int i=1;i<=len;i++)
    {
        digit[i]=n%10;
        n/=10;
    }
}

ll solve(ll n)
{
    ll ans=0;
    ll len=calchangdu(n);//计算出n的长度
    caldigit(n,len);//计算出n的每一位数据
    for(int i=len;i>=1;i--)
    {
        for(int j=0;j<digit[i];j++)
        {
            if(!(digit[i+1]==4&&j==9))
            {
                ans+=dp[i][j];
            }
        }
        if(digit[i]==9&&digit[i+1]==4)break;
    }
    return ans;
}
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        ll n;
        scanf("%I64u",&n);
        printf("%I64u\n",(n+1)-solve(n+1));
    }
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值