『8.21 模擬賽』Victory
阿新 • • 發佈:2018-08-21
con char n-1 cstring string iostream scan ans 枚舉 表示當前的狀態是遞減的,\(l=0\)表示當前沒有遇到上界,\(l=1\)表示當前遇到了上界。但是在轉移的時候有很多的細節,所以我們要慢慢分析:
題目描述
遲到大王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\)
比如,上升和下降並不是嚴格的,所以我們一定要註意一下,比如還沒有出現嚴格上升的時候的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