dp: digital dp

method one:

Step-by-step calculation for the case where each digit is a certain value

Difficulty: low

Practicality: low, only available when it is required to determine whether a digit appears in a digit

 

For example, find the case where there are no consecutive 62 and no 4 in the number

A number smaller than 456 can be considered like this,

4          5             6

4        5           (0~6)

4        (0~4)        (0~9)

(0~3)   (0~9)        (0~9)

First calculate how many numbers can satisfy ( 0~399) when the hundreds place is 0, 1, 2, and 3

Then calculate how many numbers can satisfy ( 000~049) when the tens place is 0, 1, 2, 3, and 4

Finally , how many numbers can be satisfied when the tens place is 0~6 ( 000~006)

Here it is explained that 0~49 is equivalent to 400~449

If these numbers are preceded by 4 or 62, these numbers do not count

does not appear, the value of the preceding number has no effect

 

Explain the actual operation

dp[][], the first dimension represents the number of digits (one, ten, hundred, etc.), and the second dimension represents the number of digits on the digit

First assign the initial value, obviously the value of each one except 4 is 1

 

Then the state transition equation is

dp[i][j]=dp[i-1][0]+ dp[i-1][1]+…+dp[i-1][9]

Then add the judgment of 62 and 4

FOR(i,2,6)

       {

              FOR(j,0,9)

              {

                     if(j==4) continue;

                     FOR(k,0,9)

                     {

                            if(k==4||(j==6&&k==2)) continue;

                            dp[i][j]+=dp[i-1][k];

                     }

              }

       }     

Among them , the number of digits of j is to the left of k, which is used to judge whether 62 exists or not.

 

Initialization is relatively simple, but there are many error-prone points in the solution process

First, put out each digit of the read number.

       while(k)

       {

              a[++cnt]=k%10;

              k/=10;

       }

       a[cnt+1]=0;

It is necessary to ensure that the previous bit of the largest bit of the array is 0, because this bit will be used in subsequent judgments

First from high to low

For example , 456, we first calculated 0~399, because there are 4, the following numbers are illegal

So the high-order number determines whether the low-order number is valid

So the loop ends when these numbers appear

 

If the hundreds place is 3, we want to calculate 0~299, so we actually calculate

0~99

100~199

200~299

That is, a number smaller than 3, so the range of the loop is 0~( a[i]-1)

This calculation method will calculate one less number when calculating the last digit.

For example , 123, we actually calculated 0~122, so the number to be calculated should be incremented by 1

ROF(i,cnt,1)

       {

              FOR(j,0,a[i]-1)

              {

                     if((a[i+1]==4&&j==9)) continue;

                     ans+=dp[i][j];

              }

              if((a[i+1]==4&&a[i]==9)) break;

       }

The above methods are very basic, error-prone to write and very limited in use

 

 

Method Two:

memoized search dp

Difficulty: high

Usability: high, almost all situations

 

Here first add the cognition of dp

Take the tower as an example

If you enumerate all the states, there will be a lot of very similar states with only a small difference between them, and you will be doing a lot of repetitive operations, and if you find a pattern that takes all the states that have been computed, and applies In the operations to be performed, the efficiency will be greatly improved.

However, the case of number towers is very monotonic, and when you reason about the state, the state is fully represented by just a one-dimensional array. But even so, we can still do memoized searches.

Memorized search means - after judging the state, the next time you encounter it, you can directly borrow the past results.

 

Code:

int dfs(int x,int y) 

       if(dp[x][y]) 

       return dp[x][y];

       if(x>n||y>n) return 0;

       dp[x][y]=max(dfs(x+1,y),dfs(x+1,y+1))+a[x][y]; 

       return dp[x][y]; 

}

Then dp[1][1] is the answer we need, and its operation order is consistent with the conventional state equation writing.

Therefore, we can find that dp and memoization search are closely related. If you can't understand digital dp search at present, it is better to use memoization search to rewrite previous dp questions to deepen your understanding.

 

An example of digital dp for memoized search is given below

ll dfs(int pos,int sta,int limit)

// The four parameters from 3 to 4 are the current bit, the state (may use two numbers to represent the state), and the upper limit

{

       //cout<<pos<<" "<<sta<<" "<<f[sta]<<endl;

       if(pos==0)//Go to the last digit to determine whether the number satisfies the condition

       {

              return f[sta]==1;

       }

       if(!limit&&dp[pos][sta]!=-1)

  //When the number of digits is the same and the state is the same, the past result is directly borrowed, and the limit is whether the upper limit is reached. For example, the last calculation was 1000 to 1999, which is exactly the same as the current 2000 to 2999, but the upper limit (initial input) is less than 2999, so cannot borrow

       {

              return dp[pos][sta];

       }     

       int up=limit?a[pos]:9,s,g=sta,k=sta;

       ll ans=0;

       FOR(i,0,up)

       {

              if(i==0)

              {

                     if(sta!=0)

                     {

                            s=g%3;

                            g/=3;

                            if(s==0||s==1) k=sta+t[i];

                            else k=sta-t[i];

                     }

              }

              else

              {

                     s=g%3;

                     g/=3;

                     if(s==0||s==1) k=sta+t[i];

                     else k=sta-t[i];

              }

              ans+=dfs(pos-1,k,limit&&i==up);

       }

       if(!limit)//When the upper limit is not reached, record the status

              dp[pos][sta]=ans;

       return ans;

}

ll solve(ll x)

{

    int pos=0;

    while(x)

    {

        a[++pos]=x%10;

        x/=10;

    }

    a[pos+1]=0;

    return dfs(pos,0,1);

}

 The corresponding questions correspond to SPOJ BALNUM , and the actual questions are rewritten according to the needs, and there is no generality.

By the way, let’s talk about this question first. The question requires how many BALNUM are in l and r. BALNUM means that the odd number in the digits appears even number of times, the even number appears odd number of times, and the ones that do not appear are not considered, such as 1, 111, 11111, 22 , 2222 are BALNUM.

Use ternary to represent the status of 0 to 9, 0 is not present, 1 is odd number of times, 2 is even number of times.

Since only 1 and 2 are added to the calculation, all eligible state numbers can be processed by the following binary

Note: t[j] is 3 to the j power

FOR(i,1,pow(2,10)-1)

       {

              int l = i, ret = 0;

              FOR(j,0,9)

              {

                     if(l&1) ret+=((j%2)==1?2*t[j]:t[j]);

                     l>>=1;

              }

              //cout<<i<<" "<<ret<<endl;

              f [ret] = 1;

       }

 

Guess you like

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