2017 百度之星复赛题解 01、03、05
01、
有个易错点,我卡了好久,就是 1(012)#(1) 答案是1012,我刚开始把012的前导0去掉了。。。
03、
05、
数位DP,记忆化搜索
dp[ p ][ q ][ limit ][ ceng ]:表示前一位是 p,前面处于递增(递减)状态q,当前位上限是多少limit,还有多少位ceng .
根据不同情况递归即可,可以先不写记忆化,先写暴力的,最后加上记忆化。
1 #include<stdio.h> 2 #include<string.h> 3 #define Mod 1000000007 4 #define LL long long 5 LL dp[105][11][11][2]; 6 7 LL dfs(int p, int q, int limit, int ceng){ 8 if(ceng==0){ 9 return 1; 10 } 11 if(dp[ceng][p+1][limit][q]!=-1) return dp[ceng][p+1][limit][q]; 12 13 LL ret = 0; 14 for(int i=0; i<limit; i++){ 15 if(q==0){ // 递减 16 if(p==-1 || i <= p) { 17 if(p==-1 && i==0){ 18 ret += dfs(-1, 0, 10, ceng-1); 19 } else 20 ret += dfs(i, 0, 10, ceng-1); 21 } else { 22 ret += dfs(i, 1, 10, ceng-1); 23 } 24 } else { 25 if(i < p) continue; 26 ret += dfs(i, 1, 10, ceng-1); 27 } 28 ret %= Mod; 29 } 30 31 dp[ceng][p+1][limit][q]=ret; 32 return ret; 33 } 34 35 int main(){ 36 memset(dp, -1, sizeof(dp)); 37 char n[105]; 38 int t; 39 scanf("%d", &t); 40 while(t--){ 41 scanf("%s", &n); 42 LL ans = 0; 43 int len = strlen(n); 44 int u = 0; 45 for(int i=0; i<len; i++){ 46 int limit = n[i]-'0'; 47 int p = i==0?-1:n[i-1]-'0'; 48 49 if(u==2) break; 50 51 ans += dfs(p, u, limit, len-i); 52 ans %= Mod; 53 54 if(u==0){ 55 if(i!=0 && limit>p){ 56 u=1; 57 } 58 } else if(u==1){ 59 if(limit<p){ 60 u=2; 61 } 62 } 63 } 64 printf("%I64d\n", ( (ans - 1 + (u==2?0:1) ) % Mod + Mod ) % Mod ); 65 } 66 return 0; 67 }