题目描述
有一种奇怪的语言叫做“贰五语言”。它的每个单词都由A~Y这25个字母各一个组成。但是,并不是任何一种排列都是一个合法的贰五语言单词。贰五语言的单词必须满足这样一个条件:把它的25个字母排成一个5*5的矩阵,它的每一行和每一列都必须是递增的。比如单词ACEPTBDHQUFJMRWGKNSXILOVY,它排成的矩阵如下所示:
A C E P T
B D H Q U
F J M R W
G K N S X
I L O V Y
因为它的每行每列都是递增的,所以它是一个合法的单词。而单词YXWVUTSRQPONMLKJIHGFEDCBA则显然不合法。 由于单词太长存储不便,需要给每一个单词编一个码。编码方法如下:从左到右,再从上到下,可以由一个矩阵的得到一个单词,再把单词按照字典顺序排序。比如,单词ABCDEFGHIJKLMNOPQRSTUVWXY的编码为1,而单词ABCDEFGHIJKLMNOPQRSUTVWXY的编码为2。
现在,你需要编一个程序,完成单词与编码间的转换。
输入输出格式
输入格式:第一行为一个字母N或W。N表示把编码转换为单词,W表示把单词转换为编码。
若第一行为N,则第二行为一个整数,表示单词的编码。若第一行为W,则第二行为一个合法的单词。
输出格式:每行一个整数或单词。
输入输出样例
N 2
ABCDEFGHIJKLMNOPQRSUTVWXY
W ABCDEFGHIJKLMNOPQRSUTVWXY
2
说明
题目翻译来自NOCOW。
USACO Training Section 5.5
题目思想:深搜dfs + dp + 逼近
dp[a][b][c][d][e] 表示第一行选a个,第二行选b个......(大力减少搜索时间)
把一串字符串变成5 × 5的矩阵,就像题目所说
主要思想:
比如搜字符串“ABD.....”时会有字符串“ABC.....”要在前面,那么字符串“ABD.....”之前的方案一定有在字符串“ABC.....”之前的所有方案,所有我们就可以不断加上这些小的字符串的方案,不断逼近到所求的方案
/*************************************************************************
> Author: wzw-cnyali
> Created Time: 2017/5/25 19:23:03
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define EREP(i, a) for(register int i = (be[a]); i != -1; i = nxt[i])
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define mem(a, b) memset((a), b, sizeof(a))
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template <class T>
T read(T sum = 0, T fg = 0)
{
char c = getchar();
while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }
while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }
return fg ? -sum : sum;
}
const int inf = 0x3f3f3f3f;
const int Size = 100000;
const int maxn = 100000;
const int maxm = 100000;
char S[Size];
char str[Size];
int dp[6][6][6][6][6];
bool check(int x, int now)
{
return (!S[x] || S[x] == now + 'A');
}
int dfs(int a, int b, int c, int d, int e, int now)
{
if(now == 25) return 1;
int ret = dp[a][b][c][d][e];
if(ret) return ret;
if(a < 5 && check(a, now)) ret += dfs(a + 1, b, c, d, e, now + 1);
if(b < a && check(b + 5, now)) ret += dfs(a, b + 1, c, d, e, now + 1);
if(c < b && check(c + 10, now)) ret += dfs(a, b, c + 1, d, e, now + 1);
if(d < c && check(d + 15, now)) ret += dfs(a, b, c, d + 1, e, now + 1);
if(e < d && check(e + 20, now)) ret += dfs(a, b, c, d, e + 1, now + 1);
return dp[a][b][c][d][e] = ret;
}
void work1(int n)
{
REP(i, 0, 24)
{
for(S[i] = 'A'; ; ++S[i])
{
mem(dp, 0);
int ret = dfs(0, 0, 0, 0, 0, 0);
if(ret >= n) break;
n -= ret;
}
}
printf("%s\n", S);
}
void work2()
{
int ans = 0;
REP(i, 0, 24)
{
for(S[i] = 'A'; S[i] < str[i]; ++S[i])
{
mem(dp, 0);
int ret = dfs(0, 0, 0, 0, 0, 0);
ans += ret;
}
}
printf("%d\n", ans + 1);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
freopen("output.out", "w", stdout);
#endif
char ch;
cin >> ch;
if(ch == 'N')
{
int n = read<int>();
work1(n);
}
else if(ch == 'W')
{
scanf("%s", str);
work2();
}
return 0;
}