Position:
List
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
第一行一个字母,W表示任务1,N表示任务2
若是任务1,第二行是一个优美的单词,否则第二行是一个正整数,表示某个优美的单词的编号,保证该数不超过优美的单词的总数
Output
一行,若是任务1,输出对应编号,否则输出对应的优美的单词
Sample Input
-
W
ABCDEFGHIJKLMNOPQRSUTVWXY -
N
20
Sample Output
-
2 -
ABCDEFGHIJKLMNOPQSUWRTVXY
HINT
无
Solution
普通搜索显然TLE(枚举每一位填什么字母O(26!))
注意条件每一行每一列的字母都是字典序递增→每个字母必须小于右下方所有的字母
考虑从A到Z依次填入矩阵0~24中,记忆化搜索f[a][b][c][d][e]记录当前状态后继方案数,满足a>b>c>d>e,并且当前已经填入的数要是原样,src(a,b,c,d,e,tot)tot记录要填入哪个字母。
对于第一个任务,求编号,那么每个位置可以填1~s[i]-‘A’+1,统计之前的方案数,最终方案数加上自己即可+1。
对于第二个任务,求方案,那么每个位置从’A’开始填,知道>n,最终求出的即为结果。
码题解的时候发现如果用过的字母就不要用了,加上优化发现快了不少。
Code

1 // <twofive.cpp> - Mon Sep 19 08:11:51 2016 2 // This file is made by YJinpeng,created by XuYike's black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don't know what this program is. 5 6 #include <iostream> 7 #include <vector> 8 #include <algorithm> 9 #include <cstring> 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cmath> 13 #define MOD 1000000007 14 #define INF 1e9 15 using namespace std; 16 typedef long long LL; 17 const int MAXN=6; 18 const int MAXM=36; 19 inline int max(int &x,int &y) {return x>y?x:y;} 20 inline int min(int &x,int &y) {return x<y?x:y;} 21 inline int gi() { 22 register int w=0,q=0;register char ch=getchar(); 23 while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); 24 if(ch=='-')q=1,ch=getchar(); 25 while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar(); 26 return q?-w:w; 27 } 28 char s[MAXM];int ans[MAXM]; 29 int f[MAXN][MAXN][MAXN][MAXN][MAXN]; 30 inline bool check(int x,int c){return ans[x]?ans[x]==c:1;} 31 inline int src(int a,int b,int c,int d,int e,int tot){ 32 if(tot==25)return 1; 33 int &tmp=f[a][b][c][d][e]; 34 if(tmp)return tmp; 35 if(a<5&&check(a,tot+1))tmp+=src(a+1,b,c,d,e,tot+1); 36 if(b<a&&check(b+5,tot+1))tmp+=src(a,b+1,c,d,e,tot+1); 37 if(c<b&&check(c+10,tot+1))tmp+=src(a,b,c+1,d,e,tot+1); 38 if(d<c&&check(d+15,tot+1))tmp+=src(a,b,c,d+1,e,tot+1); 39 if(e<d&&check(e+20,tot+1))tmp+=src(a,b,c,d,e+1,tot+1); 40 return tmp; 41 } 42 int main() 43 { 44 freopen("twofive.in","r",stdin); 45 freopen("twofive.out","w",stdout); 46 char type=getchar();int n=0; 47 if(type=='W'){ 48 scanf("%s",s); 49 for(int i=0;i<25;i++) 50 for(ans[i]=1;ans[i]<s[i]-'A'+1;ans[i]++){ 51 memset(f,0,sizeof(f)); 52 n+=src(0,0,0,0,0,0); 53 } 54 printf("%d",n+1); 55 }else{ 56 n=gi(); 57 for(int i=0;i<25;i++) 58 for(ans[i]=1;ans[i]<=26;ans[i]++){ 59 memset(f,0,sizeof(f)); 60 int now=src(0,0,0,0,0,0); 61 if(now>=n)break;n-=now; 62 } 63 for(int i=0;i<25;i++)putchar(int(ans[i]+'A'-1)); 64 } 65 return 0; 66 }
小优化-s

1 // <twofive.cpp> - Mon Sep 19 08:11:51 2016 2 // This file is made by YJinpeng,created by XuYike's black technology automatically. 3 // Copyright (C) 2016 ChangJun High School, Inc. 4 // I don't know what this program is. 5 6 #include <iostream> 7 #include <vector> 8 #include <algorithm> 9 #include <cstring> 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cmath> 13 #define MOD 1000000007 14 #define INF 1e9 15 using namespace std; 16 typedef long long LL; 17 const int MAXN=6; 18 const int MAXM=36; 19 inline int max(int &x,int &y) {return x>y?x:y;} 20 inline int min(int &x,int &y) {return x<y?x:y;} 21 inline int gi() { 22 register int w=0,q=0;register char ch=getchar(); 23 while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); 24 if(ch=='-')q=1,ch=getchar(); 25 while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar(); 26 return q?-w:w; 27 } 28 char s[MAXM];int ans[MAXM],used[MAXM]; 29 int f[MAXN][MAXN][MAXN][MAXN][MAXN]; 30 inline bool check(int x,int c){return ans[x]?ans[x]==c:1;} 31 inline int src(int a,int b,int c,int d,int e,int tot){ 32 if(tot==25)return 1; 33 int &tmp=f[a][b][c][d][e]; 34 if(tmp)return tmp; 35 if(a<5&&check(a,tot+1))tmp+=src(a+1,b,c,d,e,tot+1); 36 if(b<a&&check(b+5,tot+1))tmp+=src(a,b+1,c,d,e,tot+1); 37 if(c<b&&check(c+10,tot+1))tmp+=src(a,b,c+1,d,e,tot+1); 38 if(d<c&&check(d+15,tot+1))tmp+=src(a,b,c,d+1,e,tot+1); 39 if(e<d&&check(e+20,tot+1))tmp+=src(a,b,c,d,e+1,tot+1); 40 return tmp; 41 } 42 int main() 43 { 44 freopen("twofive.in","r",stdin); 45 freopen("twofive.out","w",stdout); 46 char type=getchar();int n=0; 47 memset(used,false,sizeof(used)); 48 if(type=='W'){ 49 scanf("%s",s); 50 for(int i=0;i<25;i++){ 51 for(ans[i]=1;ans[i]<s[i]-'A'+1;ans[i]++){ 52 if(used[ans[i]])continue; 53 memset(f,0,sizeof(f)); 54 n+=src(0,0,0,0,0,0); 55 } 56 used[ans[i]]=1; 57 } 58 printf("%d",n+1); 59 }else{ 60 n=gi(); 61 for(int i=0;i<25;i++){ 62 for(ans[i]=1;ans[i]<=26;ans[i]++){ 63 if(used[ans[i]])continue; 64 memset(f,0,sizeof(f)); 65 int now=src(0,0,0,0,0,0); 66 if(now>=n)break;n-=now; 67 } 68 used[ans[i]]=1; 69 } 70 for(int i=0;i<25;i++)putchar(int(ans[i]+'A'-1)); 71 } 72 return 0; 73 }
这里不得不再提起常数优化,算法优化,小优化→大分数。这点意识真的要有,说不准快了0.01s你就多过了10分,说不准多十分你就保送,进队,金牌,一等奖,降分……
来看下效果:
之后