题目描述 Description
对于包含字母A到Y各一次的单词S,将其从上到下从左到右写在一个5*5的矩阵中,如单
词ADJPTBEKQUCGLRVFINSWHMOXY写出来如下:
A D J P T
B E K Q U
C G L R V
F I N S W
H M O X Y
若该矩阵满足每一行每一列的字母都是字典序递增的则称S为优美的,如上述单词就是
优美的,而ADJPTBEGQUCKLRVFINSWHMOXY则不是(第二列不满足要求)。
Your Task
将所有优美的单词按字典序列出,从小到大编号1,2,……
请你完成以下两种任务:
1. 给定一个优美的单词,求其编号。
2. 给定一个编号,求对应的优美的单词。
输入描述
Input Description
第一行一个字母,W表示任务1,N表示任务2
若是任务1,第二行是一个优美的单词,否则第二行是一个正整数,表示某个优美的单
词的编号,保证该数不超过优美的单词的总数
输出描述
Output Description
一行,若是任务1,输出对应编号,否则输出对应的优美的单词
样例输入
Sample Input
W
ABCDEFGHIJKLMNOPQRSUTVWXY
样例输出
Sample Output
2
数据范围及提示
Data Size & Hint
样例输入二
N
20
样例输出二
ABCDEFGHIJKLMNOPQSUWRTVXY
正解:记忆化搜索
解题报告:
今天考试T5,感觉好神啊,%%%。
考虑直接搜索的话肯定会TLE,但我们可以想到一个点一定比他右下方的所有点权值小,这可以作为一个剪枝。
那么考虑记忆化搜索,f[i][j][k][l1][l2]表示第一行摆了i个,第二行摆了j个,第三行摆了k个,第四行摆了l1个,第五行摆了l2个的方案数(保证五个数不降,才能保证合法性)
然后我们如何操作呢?以N操作为例,因为我们想得到第n个字符串是什么,所以我们可以这么做:首先从1到25确定每一位填什么,比如说前三位填ABC,然后我算一下在前三位固定的情况下我统计一下这种情况的总方案数,如果大于n,那么说明前三位填ABC是可行的(因为如果已经大于n了,那么这一位再变大肯定更加大就不合法了,所以可以确定这一位就是当前搜索的数),然后继续往下找,直到发现当我确定到某一位发现小于n了,那么我就把这个方案数从n中减掉,然后我再把这一位稍微变大,再统计方案,不断反复。最后得到的序列就是我想要的序列。
W操作也是类似的,只是每一位约束上界不能超过给定的字符串,最后统计方案,输出方案+1即可(要包括自己)。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 int n; 16 char cc,ch[26]; 17 int ans[26]; 18 int f[6][6][6][6][6]; 19 //f[i][j][k][l1][l2]表示第一行摆了i个,第二行摆了j个,第三行摆了k个,第四行摆了l1个,第五行摆了l2个的方案数,保证五个数不降,才能保证合法性 20 21 inline int getint() 22 { 23 int w=0,q=0; char c=getchar(); 24 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 25 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 26 } 27 28 inline bool check(int x,int num){ return (!ans[x]) || (ans[x]==num); } 29 30 inline int dfs(int a,int b,int c,int d,int e,int tot){ 31 if(tot==25) return 1; 32 int &tmp=f[a][b][c][d][e]; 33 if(tmp) return tmp; 34 if(a<5 && check(a,tot+1)) tmp+=dfs(a+1,b,c,d,e,tot+1); //填在第一行 35 if(b<a && check(b+5,tot+1)) tmp+=dfs(a,b+1,c,d,e,tot+1); //保证严格不降 36 if(c<b && check(c+10,tot+1)) tmp+=dfs(a,b,c+1,d,e,tot+1); 37 if(d<c && check(d+15,tot+1)) tmp+=dfs(a,b,c,d+1,e,tot+1); 38 if(e<d && check(e+20,tot+1)) tmp+=dfs(a,b,c,d,e+1,tot+1); 39 return tmp; 40 } 41 42 inline void work(){ 43 cc=getchar(); 44 if(cc=='W') { 45 scanf("%s",ch); 46 for(int i=0;i<25;i++) { 47 for(ans[i]=1;ans[i]<ch[i]-'A'+1;ans[i]++) { 48 memset(f,0,sizeof(f)); 49 n+=dfs(0,0,0,0,0,0); 50 } 51 } 52 printf("%d",n+1);//加上自己 53 } 54 else { 55 n=getint(); int now; 56 for(int i=0;i<25;i++) { 57 for(ans[i]=1;ans[i]<=26;ans[i]++) {//确定状态,搜索在当前状态下的答案数 58 memset(f,0,sizeof(f));//随时清空 59 now=dfs(0,0,0,0,0,0); 60 if(now>=n) break; 61 n-=now; 62 } 63 } 64 for(int i=0;i<25;i++) printf("%c",ans[i]+'A'-1); 65 } 66 } 67 68 int main() 69 { 70 work(); 71 return 0; 72 }