【數位DP】不降數
阿新 • • 發佈:2021-10-14
【題目連結】
【題目描述】
定義一種不降數,這種數字必須滿足從左到右各位數字成小於等於的關係,如123,446。現在大家決定玩一個遊戲,指定一個整數閉區間[a,b] ,問這個區間內有多少個不降數。 【輸入】有多組測試資料。每組只含兩個數字 a,b意義如題目描述。1≤a,b≤231。
【輸出】
每行給出一個測試資料的答案,即[a,b]之間有多少不降數。
【輸入樣例】
1 9 1 19 【輸出樣例】 9 18 數位DP通常是需要按位分情況討論的,將數num劃分為anan-1...a2a1,從最高位開始到低位,劃分為0~ai-1與ai,如果第i位上填的是0~ai-1,那麼後面的所有位數都可以填0~9,如果第i位是ai那麼答案就在我們所畫的紅框內部,此外,不降數的個數,應當與 數的位數 還有 數的最高位 有關,因此我們可以使用狀態 f[i][j] 來表示 位數為i位,且最高位為j的數字的 不降數個數。
狀態表示已經解決,那麼接下來就思考如何進行狀態的計算。
對於一個i位數,最高位為j的數字,表示形式如下
j k x x x ... x
如果這個數字是不降數,那麼次高位k就應當滿足k≥j,故到此可以得出狀態轉移方程:f[i][j] = f[i - 1][j] + f[i - 1][j + 1] + f[i - 1][j + 2] + ....... + f[i - 1][9];
1 for(int i = 0;i <= 9;++i) //初始化1位數的情況,f[1][0]也是一個不降數 2 f[1][i] = 1; 3 for(inti = 2;i <= N;++i) //列舉位數i 4 for(int j = 0;j <= 9;++j)//列舉首位數字j 5 for(int k = j;k <= 9;++k)//列舉次高位數字k 6 f[i][j] += f[i - 1][k];
至此,就完成位數為i位,最高位為j的數字中不降數個數的預處理。接下來,按最開始的思想,從最高位開始,列舉每一位數字的不降數並累加得出答案。
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 const int N = 12; 6 int f[N][N]; 7 int num[N]; 8 int count(int n) 9 { 10 if(n == 0) 11 return 1; 12 int cnt = 0; 13 while(n) 14 { 15 num[++cnt] = n % 10; 16 n /= 10; 17 } 18 int res = 0; 19 int now = 0,last = 0; 20 for(int i = cnt;i > 0;--i) 21 { 22 now = num[i]; 23 for(int k = last;k < now;++k) //列舉ai~ai-1,當列舉到ai則直接跳往下一位 24 res += f[i][k]; 25 if(last > now) //當上一位比當前位大時,就沒有繼續計算的必要了,如5228,到第二位時,5 > 2,必不可能成為不降數 26 break; 27 last = now; 28 if(i == 1) //特判最後一位 29 ++res; 30 } 31 return res; 32 } 33 34 int main() 35 { 36 for(int i = 0;i <= 9;++i) 37 f[1][i] = 1; 38 for(int i = 2;i <= N;++i) 39 for(int j = 0;j <= 9;++j) 40 for(int k = j;k <= 9;++k) 41 f[i][j] += f[i - 1][k]; 42 int n,m; 43 while(cin >> n >> m) 44 cout << count(m) - count(n - 1) << endl; 45 return 0; 46 }