题目大意是,给你一串字符串,输出它的字典序的第n个回文字符串。如果没有或者没有n这么大的就输出“XXX”。
首先先考虑能不能构成回文串,首先奇数个的字母肯定只能有1个,不然肯定不能没办法构成回文串。然后要得到一个回文串,只需要算出(strlen(str)>> 1)这么长的字符串就行了,然后看看是否存在个数为奇数的字母,最后把算出来的字符串反向输出一下就OK了。
本来是打算用康托展开的,后来考虑到重复的元素是否能将重复的字母看成不重复的来算,最后花了一个下午,得出结论,不行。
最后百度了下,看了题解,原来要用搜索来做。
首先先计算一下所有的字母的个数,然后每个字母的个数直接除以2,用这个计算字符串的总排列数。接下来就直接搜索每一位,比如说对于第一位,先取出字典序最小的字母,计算第一个位置为这个字母的情况下又多少种排列数,比如说是k,如果k >= n,那么这个位置就可以确定下来了,如果k < n,, 那么这个位置放这个字母显然是不够的,需要放更大的字典序的字母进来,在继续找之前还要进行一步操作, n -= k, 因为如果对一个字符串进行全排列,肯定先排完第一个位置放字典序为最小的字母,然后才开始字典序第二大的。一直这样进行下去,这个字符串就搜索出来了。在这里写了个递归的代码,后来又改成了非递归的。
上代码:
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int MAXN = 30 + 5;
LL fact[16];
char OddChar;
int n, len, num[26];
char str[MAXN], ans[MAXN];
//计算有多少种
LL Permutation(int len)
{
LL res = fact[len];
for(int i = 0; i < 26; ++i)
res /= fact[num[i]];
return res;
}
LL MaxPalindromic()
{
memset(num, 0, sizeof(num));
for(int i = 0; str[i] != '\0'; ++i)
++num[str[i] - 'a'];
int OddNum = 0;
for(int i = 0; i < 26; ++ i)
{
if(num[i] & 1)
{
++OddNum;
OddChar = i + 'a';
}
num[i] >>= 1;
}
if(OddNum > 1)
return 0LL;
if(OddNum == 0)
OddChar = '#';
len = strlen(str) >> 1;
return Permutation(len);
}
void solve(LL x, int n)
{
for(int i = 0; i < len; ++ i)
for(int j = 0; j < 26; ++ j)
if(num[j])
{
--num[j];
LL tmp = Permutation(n - 1 - i);
if(tmp < x)
{
++num[j];
x -= tmp;
continue;
}
ans[i] = j + 'a';
break;
}
}
/*
void dfs(int cur, int n, LL x)
{
if(n == 0)
return;
for(int i = 0; i < 26; ++ i)
if(num[i])
{
--num[i];
LL tmp = Permutation(n - 1);
if(tmp < x)
{
++num[i];
x -= tmp;
continue;
}
ans[cur] = i + 'a';
dfs(cur + 1, n - 1, x);
}
}*/
int main()
{
int T;
scanf("%d", &T);
fact[0] = 1;
for(int i = 1; i < 16; ++ i)
fact[i] = fact[i - 1] * i;
for(int tCase = 1; tCase <= T; ++ tCase)
{
scanf("%s%d", str, &n);
printf("Case %d: ", tCase);
LL MaxNumber = MaxPalindromic();
if(MaxNumber < n)
puts("XXX");
else
{
//dfs(0, len, n);
solve(n, len);
for(int i = 0; i < len; ++ i)
putchar(ans[i]);
if(OddChar != '#')
putchar(OddChar);
for(int i = len - 1; i >= 0; -- i)
putchar(ans[i]);
putchar('\n');
}
}
return 0;
}