hdu3555 Bomb 【数位dp+记忆化dfs】

来源:互联网 发布:淘宝客服团队建设 编辑:程序博客网 时间:2024/06/05 03:58

题目链接:hdu3555 Bomb

题意:
t组样例,给正整数n(n<=2631),输出[1, n]中包含”49”的数的个数。


1. 传统dp
dp预处理出[0,10],[0,100]...[0,1020] 的答案,根据n每位的值按情况累加即可;
注意n包括49的情况, 例如n=234950这种情况, 49之后不再按每位值累加,而是[234900, 234950]都符合。

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;typedef long long LL;int a[25];LL dp[25][3];//dp[i][0] len <= i && 包含 49 的个数//dp[i][1] len = i && 首位是 9 && 不包含 49 的个数//dp[i][2] len <= i && 不包含 49 的个数void init(){    memset(dp, 0, sizeof(dp));    dp[0][2] = 1;    for(int i = 1; i < 22; i++)    {        //转移方程        dp[i][0] = 10 * dp[i-1][0] + dp[i-1][1];        dp[i][1] = dp[i-1][2];        dp[i][2] = 10 * dp[i-1][2] - dp[i-1][1];    }}LL sol(LL x){    int w = 0;    x++;                //答案没有算自身,统计的是(1, n)开区间,可以变为统计(1,n+1); 或者返回答案时特判+1。    while(x)    {        a[++w] = x % 10;        x /= 10;    }    a[w+1] = 0;    LL ans = 0;    int flag = false;                   //flag 表示前几位中是否存在49    for(int i = w; i > 0; i--)    {        ans += a[i] * dp[i-1][0];                if(flag)                               //前几位存在49时 剩余位全都符合 ans += a[i]*1e(i-1)          //因为1e(i-1)可以拆成dp[i-1][0]+dp[i-1][2], 只需再加上dp[i-1][2]            ans += a[i] * dp[i-1][2];            else                                   //不存在49时 0~a[i]-1已考虑 即为a[i]*dp[i-1][0],只需再考虑a[i]的情况        {            if(a[i] > 4)      //a[i]>4时 i位可以为4和i-1位为9且不含49的情况组合 一共dp[i-1][1]个                ans += dp[i-1][1];            if(a[i+1] == 4 && a[i] == 9)  //出现49 标记                flag = true;        }    }    //if(flag) ans++;    return ans;}int main(int argc, char const *argv[]){    init();    int t;    scanf("%d", &t);    while(t--)    {        LL n;        scanf("%lld", &n);        printf("%lld\n", sol(n));    }    return 0;}

2. 记忆化dfs
刚学的记忆化搜索写法,看了好久才理解,注意dp数组意义与传统dp中的不相同。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;int bit[25];LL dp[25][3];//第一维对应st = 0, 1, 2 三种情况//第二维对应位数LL dfs(int pos, int st, bool flag)//pos:当前位数//st: 高位状态      st=0: 没有49; st=1: 前一位为4; st=2: 前几位中有49。//flag:高位是否不是原数{    if(pos == 0)        return st == 2;    if(flag && dp[pos][st] != -1)        return dp[pos][st];    LL ans = 0;    int x = flag? 9: bit[pos];    for(int i = 0; i <= x; i++)    {        if(st == 2 || st == 1 && i == 9)            ans += dfs(pos-1, 2, flag || i < x);        else if(i == 4)            ans += dfs(pos-1, 1, flag || i < x);        else            ans += dfs(pos-1, 0, flag || i < x);    }    if(flag)        dp[pos][st] = ans;    return ans;}LL sol(LL x){    int len = 0;    while(x)    {        bit[++len] = x % 10;        x /= 10;    }    return dfs(len, 0, false);}int main(int argc, char const *argv[]){    int t;    memset(dp, -1, sizeof(dp));    scanf("%d", &t);    while(t--)    {        LL x;        scanf("%lld", &x);        printf("%lld\n", sol(x));    }    return 0;}
0 0
原创粉丝点击