1. 程式人生 > >數位DP入門 HDU 2089 不要62 註釋詳解

數位DP入門 HDU 2089 不要62 註釋詳解

題意:輸出一個區間【m,n】內所有不含“62"and"4" 的數字個數;n<=10^7;

 數位dp一般應用於:

  求出在給定區間[A,B]內,符合條件P(i)的數i的個數.

  條件P(i)一般與數的大小無關,而與 數的組成 有關.

具體的理論過程我就不解釋了,我看了好多的文章,最後還是直接看程式碼註釋看懂的;

所以  還是直接上程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int dp[10][10];//dp[i][j]表示第i位是數j時符合條件的數字數量
int d[10];//digit[i]表示n從右到左第i位是多少

void init()
{
  dp[0][0] = 1;
  for (int i = 1; i <= 7; ++i)//列舉第i位
    for (int j = 0; j <= 9; ++j)//表示第i位是數j時符合條件的數字數量
      for (int k = 0; k <= 9; ++k)//列舉第i-1位的情況
        if (j != 4 && !(j == 6 && k == 2))///如果符合條件 !62 && !4
          dp[i][j] += dp[i - 1][k];
}

int solve(int n)
{
  int ans = 0;
  int len = 0;
  while (n)  ///計算n的digit陣列
  {
    d[++len] = n % 10;
    n /= 10;
  }
  d[len + 1] = 0;//最高位 置零 
  //計算[0,n]區間滿足條件的數字個數
  for (int i = len; i >= 1; --i)///注意:從最高位開始列舉
  {
    for (int j = 0; j < d[i]; ++j)  //列舉第i位的取值j
    {
      if (d[i + 1] != 6 || j != 2)//第i位取j滿足條件
        ans += dp[i][j];
       
    }//第i位該狀態已經不滿足條件,則i位以後都不可能滿足條件,結束迴圈
    //例如 62...or  4... 
    if (d[i] == 4 || (d[i + 1] == 6 && d[i] == 2))
      break;
  }
  return ans;
}

int main()
{
  int m, n;
  init();
  while (scanf("%d%d", &m, &n) == 2)
  {
    if (n == 0 && m == 0) break;
    printf("%d\n", solve(n + 1) - solve(m));///用[0,m]-[0,n)即可得到區間[n,m]
  }
  return 0;
}