1. 程式人生 > >『8.21 模擬賽』Victory

『8.21 模擬賽』Victory

con char n-1 cstring string iostream scan ans 枚舉

題目描述

遲到大王rsw喜歡V這個字母,因為V代表著victory,當一個數字,從左向右數的時候,沒有出現過先遞減,再遞增的情況,就被稱作Victory數。

也就是說,這個數字可以是遞增的,也可以是遞減的,也可以是先遞減再遞增的,這個過程中可以出現相鄰數字相等的情況,但是,就是不能出現過先遞減再遞增的情況。

問題是:給定n,問:1~n之間有多少個victory數。





解題思路

我們應該一眼就能看出這是一道數位dp題,一開始用3維dp寫,狀態不夠寫掛了。。。後來改用4維就A了。

我們用dp[ i ][ j ][ k ][ l ] 來表示當前選到了第i位,當前選擇的數是j,\(k=0\)表示當前的狀態是遞增的,\(k=1\)

表示當前的狀態是遞減的,\(l=0\)表示當前沒有遇到上界,\(l=1\)表示當前遇到了上界。但是在轉移的時候有很多的細節,所以我們要慢慢分析:

比如,上升和下降並不是嚴格的,所以我們一定要註意一下,比如還沒有出現嚴格上升的時候的k一直等於1,也就是遞減的,遇到了一次嚴格遞增的我們就把k嚴格設置成0,這樣我們就可以防止重復情況的計算。

我們dfs的時候一定要註意前導0對答案的影響:比如098是一個合法的三位數,但是我們很容易漏掉他,一開始在這掛了好久,我們從每一位開始枚舉,註意枚舉最高位的時候l的取值。





代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
const LL MOD=1000000007;
char n[150];
int len,a[150];
LL dp[102][11][2][2];
inline LL dfs(int wei,int num,bool ud,bool flag){
    if(wei==1)return 1;
    if(dp[wei][num][ud][flag])return dp[wei][num][ud][flag];
    if(ud==0){
        if(flag){
            for(register int i=num;i<=a[wei-1];i++){
                if(i==a[wei-1]){
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,1);
                    dp[wei][num][ud][flag]%=MOD;
                }
                else {
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
                    dp[wei][num][ud][flag]%=MOD;
                }
            }
        }
        else {
            for(register int i=num;i<=9;i++){
                dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
                dp[wei][num][ud][flag]%=MOD;
            }
        }
        return dp[wei][num][ud][flag];
    }
    else {
        if(flag){
            for(register int i=0;i<=min(num,a[wei-1]);i++){
                if(i==a[wei-1]){
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,1);
                    dp[wei][num][ud][flag]%=MOD;
                }
                else {
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,ud,0);
                    dp[wei][num][ud][flag]%=MOD;
                }
            }
            for(register int i=num+1;i<=a[wei-1];i++){
                if(i==a[wei-1]){
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,0,1);
                    dp[wei][num][ud][flag]%=MOD;
                }
                else {
                    dp[wei][num][ud][flag]+=dfs(wei-1,i,0,0);
                    dp[wei][num][ud][flag]%=MOD;
                }
            }
        }
        else {
            for(register int i=0;i<=num;i++){
                dp[wei][num][ud][flag]+=dfs(wei-1,i,1,0);
                dp[wei][num][ud][flag]%=MOD;
            }
            for(register int i=num+1;i<=9;i++){
                dp[wei][num][ud][flag]+=dfs(wei-1,i,0,0);
                dp[wei][num][ud][flag]%=MOD;
            }
        }
        return dp[wei][num][ud][flag];
    }
}
int main(){
    scanf("%s",n+1);
    len=strlen(n+1);
    for(register int i=1;i<=len;i++){
        a[len+1-i]=(int)(n[i]-'0');
    }
    LL ans=0;
    for(register int i=1;i<=a[len];i++){
        if(i!=a[len])ans+=dfs(len,i,1,0);
        else ans+=dfs(len,i,1,1);
        ans%=MOD;
    }
    for(register int i=len-1;i>=1;i--){
        memset(dp,0,sizeof(dp));
        for(register int j=1;j<=9;j++){
            ans+=dfs(i,j,1,0);
            ans%=MOD;
        }
    }
    cout<<ans<<endl;
}

『8.21 模擬賽』Victory