Digital dp explanation (transfer)

Reprinted from: Portal
digital DP is actually very flexible, so you must not expect that one article will cover all digital DP questions. This article can only explain one situation clearly, and summarize other situations when they encounter them. In the summary, I slowly realize this idea, and in the future, maybe I can reach the level where I can use it flexibly as soon as I see the title. (In fact, DP is like this...)

The digital DP to be mentioned in this article is the simplest digital DP: topic link

The main idea of ​​the title: For multiple sets of data, each time a given interval [n, m], find the number of numbers that do not have "62" or "4" in n to m.

      For example, 62315 contains 62, and 88914 contains 4, both of which are illegal. 0 < n<=m < 1000000

Just think: If we can have a function count(int x), it can return the number of numbers between [0,x] that match the meaning of the question. So is the direct output of count(m)-count(n-1) the answer?

Ok, so now our focus is on how to make this function. We need an array. (dp is originally space for time)

We set up an array f[i][j], which represents the number of i digits, the highest digit is the number of j, and how many numbers meet the meaning of the question. For example f[1][2]=1; f[1][4]=0; f[2][6]=8 (60,61,63,64,65,66,67,68,69).

Let's not pay attention to the use of this f first, let's focus on how to find f itself. First f[1][i]=0(if i==4), f[1][i]=1(if i!=4) (0<=i<=9). This step is obvious, then according to the data range of this question, it is enough to recurse to f[7][i]. Then with a little understanding, you can come up with a recursive formula:

  f[i][j]=

    if (j==4) f[i][j]=0

    else if (j!=6) f[i][j]=Σf[i-1][k] (k=0,1,2,3,4,5,6,7,8,9)

    else if (j==6) f[i][j]=Σf[i-1][k] (k=0,1,3,4,5,6,7,8,9)

The above formula is also very obvious. If you think it is not obvious, you can think of it like this: the i-digit number, the highest digit is the qualified number of j, if j is 4, it must not meet the conditions (because the title does not allow 4), So it is 0 directly; if j is not 6, then it can be taken as long as it meets the meaning of the question, so it is the sum of f[i-1][k], k can be taken at will; if j is 6, as long as it is not 2 will do, so it is f[i-1][k], and k can be summed except for 2.

It should be explained here that 00052 is considered to be a qualified number with a length of 5 and the leading position is 0, and 052 is a qualified number with a length of 3 and a leading position of 0.

So now that we have got the f array, let's reiterate its meaning: the number of i digits, the highest digit is the number of j, and how many numbers are in line with the meaning of the question.

Now we need to focus on how to use the f array to make the function count(int x) we mentioned above, which can find out how many numbers in [0,x] meet the meaning of the question.

Then we do such a function int solve(int x) it can return how many in [0, x) match the meaning of the problem. Then solve(x+1) is actually equivalent to count(x).

So now the question is transformed into: less than x, how many numbers are in line with the meaning of the question?

It's very simple, since it is less than, starting from the highest bit, there must be one bit that is strictly less than x (the previous ones are equal). So we enumerate which bit is strictly less than (the previous ones are all equal).

Suppose we now divide x into an array of a1, a2,..., aL, the length is L, and aL is the highest bit.

Then the result is actually like this: the length is L, the highest bit is the sum of all the random numbers of [0, aL-1]; plus the length is L-1, the highest bit is aL, and the second highest bit is [0 ,aL-1-1] the sum of all the random numbers that match the question; plus...; until the first one.

The reason why there is a sentence above is bold because it is not correct, but for the sake of appearance, it is written like this first. Because we also need to consider this situation: if the highest bit aL is 4, then this sentence can be terminated directly, because the sentence in front of the bolded sentence "the highest bit is aL" cannot be established. Also consider this situation: if the highest bit aL is 6, then not all of [0, aL-1-1] can be taken here (2). After adding these conditions, it is very strict.

Corresponding the above Chinese characters to the title is the f[L][0..aL-1] f[L-1][0..aL-1-1] that we obtained earlier, so after a little thought, Can write programs.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iomanip>
#include<algorithm>
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a<b?a:b)
#define swap(a,b)  (a=a+b,b=a-b,a=a-b)
#define memset(a,v)  memset(a,v,sizeof(a))
#define X (sqrt(5)+1)/2.0  //Wythoff
#define Pi acos(-1)
#define e  2.718281828459045
#define eps 1.0e-8
using namespace std;
typedef long long int LL;
typedef pair<int,int>pa;
const int MAXL(1e5);
const int INF(0x3f3f3f3f);
const int mod(1e9+7);
int dir[4][2]= {{-1,0},{1,0},{0,1},{0,-1}};
LL dp[10][20];
void getDp()
{
    memset(dp,0);
    dp[0][0]=1;
    for(int i=1;i<=7;i++)
    {
        for(int j=0;j<=9;j++)
        {
            if(j==4)
                dp[i][j]=0;
            else if(j==6)
            {
                for(int k=0;k<=9;k++)
                {
                    if(k!=2)
                        dp[i][j]+=dp[i-1][k];
                }
            }
            else
            {
                for(int k=0;k<=9;k++)
                    dp[i][j]+=dp[i-1][k];
            }
        }
    }
}
int a[20];
LL solve(int n)
{
    int len=0;
    while(n)
        a[++len]=n%10,n/=10;
    a[len+1]=0;
    LL ans=0;
    for(int i=len;i>=1;i--)
    {
        for(int j=0;j<a[i];j++)
        {
            if(j==4||a[i+1]==6&&j==2)
                continue;
            else
                ans+=dp[i][j];
        }
        if(a[i]==4)
            break;
        if(a[i+1]==6&&a[i]==2)
            break;
    }
    return ans;
}
int main()
{
    getDp();
    int n,m;
    while(cin>>m>>n&&(m||n))
    {
        LL ans1=solve(m);
        LL ans2=solve(n+1);
        cout<<ans2-ans1<<endl;
    }
}





Guess you like

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