比赛时候推出了dp,但时间不够了,没敲出来,结束后理了下思路,并不算很难
平常做按位dp,比如说求某一个范围内满足某个要求的数字串第几个是多少,dp[i][j] 表示位数为i时以j开头的串多少个,这题就算一个加强版,求价值为V的第I个串,就可以用一个dp[i][j]表示价值为i时第一个字符为j的串的个数,他还有一个空格的限制,于是dp外加一维dp[i][j][k]用k表示空格数,方程推起来也简单,注意好不能连续空格就行了,然后从前往后去确定对应位置的字符
标程用的是dp[75][20][2]的方法,不太清楚是怎么做的,第三维表示首位是否为空格????
1 #include<cstdio>
2 #include<cstring>
3 using namespace std;
4
5
6 __int64 dp[100][30][30];
7
8 int ans[100];
9 int main(){
10 memset(dp,0,sizeof(dp));
11 dp[0][1][0]=1;
12 for(int i=2;i<=75;i++){
13 for(int j=1;j<=27;j++){
14 for(int k=0;k<=20;k++){
15 __int64 val=0;
16 if(j==1){
17 if(k==0) continue;
18 for(int jj=2;jj<=27;jj++){
19 if(i>=j) val+=dp[i-j][jj][k-1];
20 }
21 }else{
22 for(int jj=1;jj<=27;jj++){
23 if(i>=j) val+=dp[i-j][jj][k];
24 }
25 }
26 dp[i][j][k]=val;
27 }
28 }
29 }
30
31 int t,cas=0;
32 scanf("%d",&t);
33 while(t--){
34 int V,W;
35 __int64 I;
36 scanf("%d%d%I64d",&V,&W,&I);
37 printf("Case #%d: ",++cas);
38 W-=1;
39 I-=1;
40 ans[0]=-1;
41 for(int i=2;i<=27;i++){
42 // printf("%d %d %d %I64d: %I64d\n",V,i,W,I,dp[V][i][W]);
43 if(I>=dp[V][i][W]){
44 I-=dp[V][i][W];
45 }else{
46 V-=i;
47 ans[0]=i;
48 break;
49 }
50 }
51 if(ans[0]==-1){
52 puts("Corrupted!");
53 continue;
54 }
55 int cnt=1;
56 bool flag=false;
57 while(true){
58 for(int i=1;i<=27;i++){
59 if(flag&&(i==1)) continue;
60 if((W==0)&&(i==1)) continue;
61 flag=false;
62 // printf("%d %d %d %I64d: %I64d\n",V,i,W,I,dp[V][i][W]);
63 if(I>=dp[V][i][W]){
64 I-=dp[V][i][W];
65 }else{
66 V-=i;
67 if(i==1){W-=1;flag=true;}
68 ans[cnt++]=i;
69 break;
70 }
71 }
72 if(V==0) break;
73 }
74 for(int i=0;i<cnt;i++){
75 if(ans[i]==1) putchar(' ');
76 else putchar(ans[i]-2+'a');
77 }
78 puts("");
79 }
80 }