1082. 數字遊戲 (數位DP)

林黛玉倒拔垂楊柳發表於2020-10-03

題目連結:點此跳轉

題目大意:
科協裡最近很流行數字遊戲。

某人命名了一種不降數,這種數字必須滿足從左到右各位數字呈非下降關係,如 123,446。

現在大家決定玩一個遊戲,指定一個整數閉區間 [a,b],問這個區間內有多少個不降數。

輸入格式
輸入包含多組測試資料。

每組資料佔一行,包含兩個整數 a 和 b。

輸出格式
每行給出一組測試資料的答案,即 [a,b] 之間有多少不降數。

資料範圍
1≤ a ≤ b ≤231−1

解題思路:
f[i][j] 陣列代表著最高位是j並且一共有i位不降數的集合
f[i][j] = f[i-1][j] + f[i-1][j+1] + f[i-1][j+2] +…+ f[i-1][9];

按照數位DP分析步驟: 假設我們當前列舉到第i位,且第i位上的數字是x,那麼現在對於答案的第i位數字j來說,可以填兩類數字:

  1. j 取0~x-1 那麼res += f[i+1][j];

  2. j 取 x last記錄x,再列舉下一位

Code:

#include<iostream>
#include<vector>
using namespace std;
const int maxn=30;

int f[maxn][maxn];

void init(){          //預處理f陣列
    for(int i=0;i<=9;i++) f[1][i]=1;
    
    for(int i=2;i<maxn;i++){
        for(int j=0;j<=9;j++){
            for(int k=j;k<=9;k++){
                f[i][j]+=f[i-1][k];
            }
        }
    }
}

int solve(int n){
    if(!n) return 1;
    vector<int> nums;
    while(n) nums.push_back(n%10),n/=10;
    
    int res=0;
    int last=0;
    for(int i=nums.size()-1;i>=0;i--){
        int x=nums[i];
        
        for(int j=last;j<x;j++){
            res+=f[i+1][j];  //(0~i位,一共有i+1位)
        }
        if(x<last) break;
        last=x;
        
        if(!i) res++; 
    }
    return res;
}

int main(){
    
    init();
    int a,b;
    while(~scanf("%d%d",&a,&b)){
        printf("%d\n",solve(b)-solve(a-1));
    }
    
}

相關文章