2015
04-16

# Cipher

A spy is using a clever cipher technique to encode and decode messages.
The technique is very efficient as it enables him to send and receive any message, no matter how long it is with only three numbers!
After many great efforts, The Department of National Security managed to figure out how the technique works:
1. First of all, the only characters used are the space and lower case English letters. Each character is assigned an integer called the character volume, a space character has volume 1, ‘a’ has volume 2, ‘b’ has volume 3 and so on until ‘z’ which has volume 27. The volume of the whole message V is the sum of volumes of characters in the message.
2. A message consists of a number of words W, a word is a consecutive sequence of lower case letters, messages have no leading or trailing spaces and there is only one space between consecutive words.
3. For a certain V and W, let S be the lexicographically sorted set of messages that have volume V and consists of exactly W words. We can refer to a certain message using its one-based index I in S.
So when the spy wants to send a message M, he calculates its Volume V and the number of words it contains W and finds its index I in the corresponding set S (its index among all sorted messages of volume V with W words) and sends only three numbers along: V, W and I!
The Department of National Security has done a great effort so far, yet they seek your help to decode messages sent by the spy! That is, given V, W and I you must decrypt the spy’s message or determine that there is no such one!

The first line of input contains an integer (1 <= T <= 200), the number of test cases.
Each data set consists of a line with three integers the volume of the message (1 <= V <= 75), the number of words (1 <= W <= 20), and the index of message (1 <= I <= 1018).

The first line of input contains an integer (1 <= T <= 200), the number of test cases.
Each data set consists of a line with three integers the volume of the message (1 <= V <= 75), the number of words (1 <= W <= 20), and the index of message (1 <= I <= 1018).

3
7 2 3
2 1 2
50 2 39098532022

Case #1: aa a
Case #2: Corrupted!
Case #3: big bang

Hint
In the first test case, the sorted set of messages of volume 7 which contain 2 words is {“a aa”, “a c”, “aa a”,
“b b”, “c a”}, hence the third and required message is “aa a”.
In the second test case, the sorted set of messages of volume 2 which contain 1 word is {“a”}, the set has
only one message while index 2 is required, so something must have gone wrong!


 #include<cstdio>
#include<cstring>
using namespace std;

__int64 dp[100][30][30];

int ans[100];
int main(){
memset(dp,0,sizeof(dp));
dp[0][1][0]=1;
for(int i=2;i<=75;i++){
for(int j=1;j<=27;j++){
for(int k=0;k<=20;k++){
__int64 val=0;
if(j==1){
if(k==0) continue;
for(int jj=2;jj<=27;jj++){
if(i>=j) val+=dp[i-j][jj][k-1];
}
}else{
for(int jj=1;jj<=27;jj++){
if(i>=j) val+=dp[i-j][jj][k];
}
}
dp[i][j][k]=val;
}
}
}

int t,cas=0;
scanf("%d",&t);
while(t--){
int V,W;
__int64 I;
scanf("%d%d%I64d",&V,&W,&I);
printf("Case #%d: ",++cas);
W-=1;
I-=1;
ans[0]=-1;
for(int i=2;i<=27;i++){
//            printf("%d %d %d %I64d: %I64d\n",V,i,W,I,dp[V][i][W]);
if(I>=dp[V][i][W]){
I-=dp[V][i][W];
}else{
V-=i;
ans[0]=i;
break;
}
}
if(ans[0]==-1){
puts("Corrupted!");
continue;
}
int cnt=1;
bool flag=false;
while(true){
for(int i=1;i<=27;i++){
if(flag&&(i==1)) continue;
if((W==0)&&(i==1)) continue;
flag=false;
//                printf("%d %d %d %I64d: %I64d\n",V,i,W,I,dp[V][i][W]);
if(I>=dp[V][i][W]){
I-=dp[V][i][W];
}else{
V-=i;
if(i==1){W-=1;flag=true;}
ans[cnt++]=i;
break;
}
}
if(V==0) break;
}
for(int i=0;i<cnt;i++){
if(ans[i]==1) putchar(' ');
else putchar(ans[i]-2+'a');
}
puts("");
}
}


1. 可以参考算法导论中的时间戳。就是结束访问时间，最后结束的顶点肯定是入度为0的顶点，因为DFS要回溯