数位DP入门之hdu 3555 Bomb

hdu 3555 Bomb
题意:
在1~N(1<=N<=2^63-1)范围内找出含有 ‘49’的数的个数;

hdu 2089 不要62的区别:2089是找不不含 '4'和 '62'的区间范围内的数,此题是含有;正好相反,对于 "不要62"只是用第二位表示首位数字,这一题呢?

看转化:易知一定要要知道首位是9的个数,才能在前面加4得到 '49',但是什么状态能从不含 '49'转移到含 '49'?直接在不含'49'前加9,那么就出现了三个状态之间的递推转化,从而推出了第二维要使用三个状态来得出长度为i时的所有情况;
二维的状态:
[0]:只是不含 '49',不管首位(可以是9); [1]:不含 '49',但首位是9; [2]:含有 '49'

#include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(i = 0;i < (n);i++)
typedef long long ll;
ll f[25][3];
void init()
{
    f[0][0] = 1;
    for(int i = 1;i <= 20;i++){
        f[i][0] = f[i-1][0] * 10 - f[i-1][1];
        f[i][1] = f[i-1][0];    // start with 9
        f[i][2] = f[i-1][1] + f[i-1][2]*10;  // contian 49
    }
}
ll query(ll n)
{
    int d[25]={},tot = 0;
    while(n){
        d[++tot] = n % 10;
        n /= 10;
    }
    ll ans = 0,flag = 1;
    for(int i = tot;i > 0;i--){
        ans += f[i-1][2]*d[i];
        if(flag && d[i] > 4) ans += f[i-1][1];
        if(!flag) ans += f[i-1][0]*d[i];
        if(d[i+1] == 4 && d[i] == 9) flag = 0;
    }
    return ans;
}
int main()
{
    init();
    int T;
    cin>>T;
    while(T--){
        ll n;
        scanf("%I64d",&n);
        printf("%I64d
",query(n+1));
    }
}
View Code
 
原文地址:https://www.cnblogs.com/hxer/p/5185134.html