Codevs1322 单词矩阵
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
// <twofive.cpp> - Mon Sep 19 08:11:51 2016
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
#define INF 1e9
using namespace std;
typedef long long LL;
const int MAXN=6;
const int MAXM=36;
inline int max(int &x,int &y) {return x>y?x:y;}
inline int min(int &x,int &y) {return x<y?x:y;}
inline int gi() {
register int w=0,q=0;register char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')q=1,ch=getchar();
while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
return q?-w:w;
}
char s[MAXM];int ans[MAXM];
int f[MAXN][MAXN][MAXN][MAXN][MAXN];
inline bool check(int x,int c){return ans[x]?ans[x]==c:1;}
inline int src(int a,int b,int c,int d,int e,int tot){
if(tot==25)return 1;
int &tmp=f[a][b][c][d][e];
if(tmp)return tmp;
if(a<5&&check(a,tot+1))tmp+=src(a+1,b,c,d,e,tot+1);
if(b<a&&check(b+5,tot+1))tmp+=src(a,b+1,c,d,e,tot+1);
if(c<b&&check(c+10,tot+1))tmp+=src(a,b,c+1,d,e,tot+1);
if(d<c&&check(d+15,tot+1))tmp+=src(a,b,c,d+1,e,tot+1);
if(e<d&&check(e+20,tot+1))tmp+=src(a,b,c,d,e+1,tot+1);
return tmp;
}
int main()
{
freopen("twofive.in","r",stdin);
freopen("twofive.out","w",stdout);
char type=getchar();int n=0;
if(type=='W'){
scanf("%s",s);
for(int i=0;i<25;i++)
for(ans[i]=1;ans[i]<s[i]-'A'+1;ans[i]++){
memset(f,0,sizeof(f));
n+=src(0,0,0,0,0,0);
}
printf("%d",n+1);
}else{
n=gi();
for(int i=0;i<25;i++)
for(ans[i]=1;ans[i]<=26;ans[i]++){
memset(f,0,sizeof(f));
int now=src(0,0,0,0,0,0);
if(now>=n)break;n-=now;
}
for(int i=0;i<25;i++)putchar(int(ans[i]+'A'-1));
}
return 0;
}
小优化-s
// <twofive.cpp> - Mon Sep 19 08:11:51 2016
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
#define INF 1e9
using namespace std;
typedef long long LL;
const int MAXN=6;
const int MAXM=36;
inline int max(int &x,int &y) {return x>y?x:y;}
inline int min(int &x,int &y) {return x<y?x:y;}
inline int gi() {
register int w=0,q=0;register char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')q=1,ch=getchar();
while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar();
return q?-w:w;
}
char s[MAXM];int ans[MAXM],used[MAXM];
int f[MAXN][MAXN][MAXN][MAXN][MAXN];
inline bool check(int x,int c){return ans[x]?ans[x]==c:1;}
inline int src(int a,int b,int c,int d,int e,int tot){
if(tot==25)return 1;
int &tmp=f[a][b][c][d][e];
if(tmp)return tmp;
if(a<5&&check(a,tot+1))tmp+=src(a+1,b,c,d,e,tot+1);
if(b<a&&check(b+5,tot+1))tmp+=src(a,b+1,c,d,e,tot+1);
if(c<b&&check(c+10,tot+1))tmp+=src(a,b,c+1,d,e,tot+1);
if(d<c&&check(d+15,tot+1))tmp+=src(a,b,c,d+1,e,tot+1);
if(e<d&&check(e+20,tot+1))tmp+=src(a,b,c,d,e+1,tot+1);
return tmp;
}
int main()
{
freopen("twofive.in","r",stdin);
freopen("twofive.out","w",stdout);
char type=getchar();int n=0;
memset(used,false,sizeof(used));
if(type=='W'){
scanf("%s",s);
for(int i=0;i<25;i++){
for(ans[i]=1;ans[i]<s[i]-'A'+1;ans[i]++){
if(used[ans[i]])continue;
memset(f,0,sizeof(f));
n+=src(0,0,0,0,0,0);
}
used[ans[i]]=1;
}
printf("%d",n+1);
}else{
n=gi();
for(int i=0;i<25;i++){
for(ans[i]=1;ans[i]<=26;ans[i]++){
if(used[ans[i]])continue;
memset(f,0,sizeof(f));
int now=src(0,0,0,0,0,0);
if(now>=n)break;n-=now;
}
used[ans[i]]=1;
}
for(int i=0;i<25;i++)putchar(int(ans[i]+'A'-1));
}
return 0;
}
这里不得不再提起常数优化,算法优化,小优化→大分数。这点意识真的要有,说不准快了0.01s你就多过了10分,说不准多十分你就保送,进队,金牌,一等奖,降分……
来看下效果:
之后