https://i.loli.net/2019/07/25/5d39b5315c60935716.jpg

2019年9月训练(壹)数位DP (HDU 2089)

开学之后完全没时间写博客....

HDU 2089 不要62(vjudge) 数位DP

思路:

题目给出区间[n,m] ,找出不含4或62的数的个数

用一个简单的差分:先求0~m+1的个数,再减去0~n的个数.

但问题依旧不简单,再次简化为求0~i位数中不含4或62的数的个数.

i=1 //0~9中
i=2 //0~99中
i=3 //0~999中
......
dp[i][0] //0~i位数中的吉利数
dp[i][1] //0~i位数中以2打头的吉利数
dp[i][2] //0~i位数中的非吉利数(含4或62)

所以第i位数中的吉利数个数为:

dp[i][0]=dp[i-1][0]*9-dp[i-1][i]

第i位数中以2打头的幸运数个数为:

dp[i][1]=dp[i-1][0]

第i位数中的非吉利数个数为:

dp[i][2]=dp[i-1][2]*10+dp[i-1][0]+dp[i-1][1]

同时初始值为:

dp[0][0]=1;
dp[0][1]=0;
dp[0][2]=0;

AC码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int dp[10][5];

void INIT()
{
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
    for(int i=1;i<=8;i++)
    {
        dp[i][0]=dp[i-1][0]*9-dp[i-1][1];//在吉利数首位补除了4的9个数,减去在2前补6的个数 
        dp[i][1]=dp[i-1][0];//吉利数在首位补2 
        dp[i][2]=dp[i-1][2]*10+dp[i-1][0]+dp[i-1][1];//不吉利的情况 
    }
}

int work(int x)
{
    int d[20],cnt=0,temp=x;
    while(temp)
    {
        d[++cnt]=temp%10;
        temp/=10;
    }
    d[cnt+1]=0;
    int flag=0,ans=0;
    for(int i=cnt;i>0;i--)
    {
        ans+=d[i]*dp[i-1][2];//用前一位所以不吉利数推出 
        if(flag) ans+=d[i]*dp[i-1][0];// 之前有不吉利数 
        else
        {
            if(d[i]>4) ans+=dp[i-1][0];//4 
            if(d[i]>6) ans+=dp[i-1][1];//6 
            if(d[i+1]==6&&d[i]>2) ans+=dp[i][1];//62 
        }
        if(d[i]==4||(d[i+1]==6&&d[i]==2)) flag=1;
    }
    return x-ans;//减去不吉利数的个数 
}

int main()
{
    int m,n;
    INIT();
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0) break;
        printf("%d\n",work(m+1)-work(n));
    }
    return 0;
} 

2019-09-16 18:50:26

posted @ 2019-09-16 18:51  plzplz  阅读(165)  评论(0编辑  收藏  举报
https://i.loli.net/2019/07/25/5d39c1d4c249939054.jpg