hdu 2089 digital dp

Link: https://vjudge.net/problem/23625/origin

Chinese, needless to say the topic.

In fact, the data of this question is very small, so direct violence can also be passed, but you still need to learn digital dp, because not every question has such small data, here is my violent code and digital dp code (digital dp is actually There is also a rough template).

Violence:

#include<stdio.h>
#include<string.h>
int dp[1000005];
int n,m,k,t;
int jug(int a)
{
    while(a)
    {
        if(a%10==4)
        return 0;
        if(a%10==2&&a/10%10==6&&a>=62)
        return 0;
        a/=10;
    }
    return 1;
}
intmain ()
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=1000000;i++)
    {
        if(jug(i))
        dp[i]=dp[i-1]+1;
        else
        dp[i]=dp[i-1];
    }
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n&&!m)
        break;
        if(m<n)
        printf("%d\n",0);
        else
        printf("%d\n",dp[m]-dp[n-1]);
    }
    return 0;
 }

Next, I will just talk about my opinion, which may not be very accurate, but it is good to have a general understanding. Now suppose we find the number of qualified numbers from 0 to 625, then we store each digit of 625 into a digit array, first introduce the order of our recursion (the value can never exceed 625), first take the hundreds digit out, because the hundreds place is 6, then we can find it like this

First find the hundreds digit, the upper bound of the hundreds digit is 6, so the hundreds digit is constrained, and the maximum can only be 6, so the hundreds digit can be 0, 1, 2, 3, 4, 5, and 6.

Next, find the ten digits, 0_ _, 1_ _, 2_ _, 3_ _, 4_ _, 5_ _, the ten digits in front of them are not restricted and can be taken at will (such as 00_, 01_,... 09_, 10_, 11_...19_...59_), from 0 to 9.

But when it comes to 6 (6_ _), it is necessary to control the following numbers, because its tens place can only take 2 at most, so we can only take 6 0 _, 6 1_, 6 2 _, and similarly, when we recurse to the tens place, If the hundreds digit is 0 to 5, then their ones digit is also unconstrained, so it can also be taken arbitrarily,

But if the hundreds digit is 6, then we have to look at the situation again. If it is 60_, or 61_, then their ones digit is also unconstrained and can be taken at will, but if it is 62_, then its one digit is subject to Constrained, the maximum can only be 5.

It should be almost the same. In the program, we recurse from the highest bit to the one bit, and at the same time save the value of the unconstrained state of the current bit , pos means it is now.

Which digit (hundreds? tens? ones?), flag indicates whether the condition (0 or 1) is met until the current state, pre indicates the previous digit of the current state (judging whether there is 62), The limit is the key to control the upper bound. We initialize it to 1, indicating that its highest bit is currently limited. In the following process

If the limit is 0, then all the numbers in the recursive process are from 0 to 9, which can be taken and stored in memory. It may not be particularly clear from the text.

Let's take a look at the code:

#include<stdio.h>
#include<string.h>
int dp[10][15][5];
int digit[15];
int n,m,k,t;
void init()
{
    memset(dp,-1,sizeof(dp));
}
int dfs( int pos, int flag, int pre, int limit) // The current bit, whether the condition is met, the previous bit, the upper control limit 
{
     if (!pos) // When the one bit is reached, the return value 
    return flag;
     if ( !limit&&dp[pos][pre][flag]!=- 1 ) // Directly output the value recorded before, saving time 
    return dp[pos][pre][flag];
     int num=limit?digit[pos]: 9 ; // Very critical thing, if limit is 1, then this position is constrained, the maximum can only be digit[pos] 
    int s= 0 ;                     // Otherwise it is not constrained and can be any value 
    for (int i=0;i<=num;i++)
    {
        if(pre==6&&i==2||!flag||i==4)
        s +=dfs(pos- 1 , 0 ,i,limit&&i==num); // this limit&&i==num is to determine whether the next digit is constrained 
        else 
        s +=dfs(pos- 1 , 1 ,i, limit&&i== num);
    }
    if(!limit&&dp[pos][pre][flag]==-1)//记录 
    dp[pos][pre][flag]=s;
    return s;
    
}
int cal(int  a)
{
    int len ​​= 0 ;
    memset(digit,0,sizeof(digit));
    while(a)
    {
        digit [ ++ len] = a% 10 ;
        a/=10;
    }
    return dfs(len,1,0,1);
}
intmain ()
{
    init();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n&&!m)
        break;
        printf("%d\n",cal(m)-cal(n-1));
    }
    return n;
 }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325254089&siteId=291194637