HDU3555 Bomb(数位DP)

数位DP入门级题目(我也只会做入门级题目0 0),求n以内的数字中不含有连续的49的数字有多少个。类似于另外一题http://acm.hdu.edu.cn/showproblem.php?pid=2089,照搬代码吧。另外一题题解,N久以前发的:传送门

先预处理,设dp[i][j]表示第i位数是j的方案数(j可以是0),不难得到dp[i][j] = sigma(dp[i-1][k])(0<=k<=9,k≠4且j≠9)。

模拟一下求和的原理,假设n = 23495,那么len = 5;第一遍循环求出来1xxxx和0xxxx的总方案数,也就是小于20000的总方案数;第二遍循环求出来20xxx和21xxx还有22xxx的总方案数;同理,第三遍求出来230xx,231xx,232xx,233xx;第四遍2340x,2341x,2342x,2343x,2344x,2345x,2346x,2347x,2348x,下一个是2349x,这个时候出现了49再求下去没有意义,于是循环终止。

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL dp[25][10];
int digit[20];
void init()
{
    dp[0][0] = 1;
    for(int i = 1; i <= 20; i++)
    {
        for(int j = 0; j <= 9; j++)
            for(int k = 0; k <= 9; k++)
            {
                if(k == 9&&j == 4) continue;
                dp[i][j] += dp[i-1][k];
            }
    }
}
void dig(LL x,int &len)
{
    memset(digit,0,sizeof digit);
    while(x)
    {
        digit[++len] = x%10;
        x /= 10;
    }
}
LL cal(LL n)
{
    LL ans = 0;
    int len = 0;
    dig(n,len);
    for(int i = len; i >= 1; i--)
    {    
        for(int j = 0; j < digit[i]; j++)
        {    
            ans += dp[i][j];
        }    
        if(digit[i] == 9&&digit[i+1] == 4) break;
    }
    return ans;
}
int main()
{
    init();
    int T;
    LL n;
    cin>>T;
    while(T--)
    {
        cin>>n;
        cout<<n+1-cal(n+1)<<endl;
    }
}
点赞