HDU 3555 Bomb(数位DP)

http://acm.hdu.edu.cn/showproblem.php?pid=3555

题意:0-n之间有多少个数包含"13"的

分析:dp[pos][have]

         pos代表当前的位置
         have0表示前面出现的数字里没有49
         have1表示前面结尾的位置是4
         have2表示前面出现的数字里有49了

#include<string.h>

#include<stdio.h>

const int MN=100;

#define LL long long

LL dp[MN][10];//dp[i,j]i长度可以任意数的个数

int digit[MN];

LL n;



//have0表示前面的没有49,have1表示已4结尾,have2表示前面包含了49

LL DFS(int pos,int have,int doing)//pos表当前位置

{

    if(pos==-1) return have==2;

    //表示后面长度可以任意数且已经搜索过

    if(!doing && dp[pos][have]!=-1) return dp[pos][have];

    int end=doing?digit[pos]:9;

    LL ans=0;

    for(int i=0; i<=end; i++)

    {

        int nhave=have;

        if(have==0 && i==4)

            nhave=1;

        if(have==1 && i==9)

            nhave=2;

        if(have==1 && i!=9)

            nhave=0;

        if(have==1 && i==4)//前面的数十4,如果当前的是4,这种情况别忘记

            nhave=1;

        ans+=DFS(pos-1,nhave,doing && i==end);

        //前面取到了最大数,后面的数不能任意取了

    }

    if(!doing)

    {//在pos以后为可以取任意数的情况下,这种状态是饱满的,做一个记忆储存,供后面查询使用

        dp[pos][have]=ans;

    }

    return ans;

}



LL cal()

{

    int len=0;

    while(n)

    {

        digit[len++]=n%10;

        n/=10;

    }

    return DFS(len-1,0,1);

}



int main()

{

    int i,j,T;

    scanf("%d",&T);

    while(T--)

    {

        scanf("%I64d",&n);

        memset(dp,-1,sizeof(dp));

        printf("%I64d\n",cal());

    }

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)