hdu 3555 Bomb 经典数位DP

本文介绍了一种高效算法,用于计算1到N范围内所有数字中连续出现49序列的次数。通过动态规划和深度优先搜索两种方法实现,并提供完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:Bomb

题目大意

给定一个整数N,求1~N中连续49的个数

解题思路

dp[i][0]表示长度为i位,不包含49的个数
dp[i][1]表示长度为i位,第一位是9的个数
dp[i][2]表示长度为i位,包含49的个数

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int MX = 69;
const int INF = 0x3f3f3f3f;
__int64 dp[MX][MX];

void init()
{
    memset(dp,0,sizeof dp);
    dp[0][0] = 1;
    for(int i=1; i<MX; i++)
    {
        dp[i][0] = dp[i-1][0]*10 - dp[i-1][1];//最高位有⑩种可能,但是要减去49开头的
        dp[i][1] = dp[i-1][0];//最开头是9后面的所有位不固定
        dp[i][2] = dp[i-1][2]*10 + dp[i-1][1];//前i-1位中包含49的并且加上i-1位中9开头的
    }
}

__int64 solve(__int64 n)
{
    int len = 0,digit[MX],flag = 0;
    __int64 ans=0;
    while(n)
    {
        digit[++len] = n%10;
        n/=10;
    }
    digit[len+1] = 0;
    for(int i=len; i; i--)
    {
        ans+=dp[i-1][2]*digit[i];
        if(flag)  ans+=dp[i-1][0]*digit[i];
        if(!flag && digit[i]>4) ans += dp[i-1][1];
        if(digit[i+1]==4&&digit[i]==9) flag = 1;
    }
    return ans;
}
int main()
{
    __int64 T,N;
    init();
    cin>>T;
    while(T--)
    {
        cin>>N;
        cout<<solve(N+1)<<endl;
    }
    return 0;
}

使用DFS的方式

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int MX = 66;
__int64 dp[MX][MX][MX],digit[MX];

__int64 DFS(int pos,bool have,int last,int limit)
{
    if(pos==-1) return have;
    if(!limit && dp[pos][have][last]!=-1) return dp[pos][have][last];
    int endP = limit?digit[pos]:9;
    __int64 ans=0;
    for(int i=0;i<=endP;i++){
        if(last==4&&i==9) ans+=DFS(pos-1,true,i,limit&&(i==endP));
        else ans+=DFS(pos-1,have,i,limit&&(i==endP));
    }
    if(!limit) dp[pos][have][last] = ans;
    return ans;
}
__int64 solve(__int64 n)
{
    int len = 0;
    while(n){
        digit[++len] = n%10;
        n/=10;
    }
    return DFS(len,false,0,1);
}
int main()
{
    __int64 N;
    int T;
    cin>>T;
    while(T--){
        memset(dp,-1,sizeof dp);
        cin>>N;
        cout<<solve(N)<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值