题意:给一个字符串,把它的所有回文串按字典序排序,然后给了个n,要求输出第n个回文串是什么,如果没有就输出XXX。
题解:首先判断是否存在第n个回文串,用一个数组f[i]表示A(i),那么一个字符串的排列方式就有A(len) / A(i),其中len是字符串长度,i是指第i个字符的个数,然后先将字典序最小的字母放到两端,然后判断此时剩下的字符串有x种排法,如果x < n说明第一位不是字典序最小的,那么n -= x,否则就让字典序最小的字母放入结果串内,让剩下的字符串以此类推,直到结果串长度达到初始串的一半。
#include <stdio.h>
#include <string.h>
using namespace std;
const int N = 40;
char str[N], ans[N];
int n, m[N];
long long f[N];
void init() {
f[0] = 1;
for (int i = 1; i <= 16; i++)
f[i] = f[i - 1] * i;
}
long long get_num(int x) {
long long sum = 1;
for (int i = 0; i < 26; i++)
sum *= f[m[i]];
return f[x] / sum;
}
int main() {
init();
int t, cas = 1;
scanf("%d", &t);
while (t--) {
scanf("%s%d", str, &n);
printf("Case %d: ", cas++);
memset(m, 0, sizeof(m));
int len = strlen(str);
for (int i = 0; i < len; i++)
m[str[i] - 'a']++;
int flag = 0, cnt = 0;
char cc;
for (int i = 0; i <= 25; i++) {
if (m[i] % 2) {
flag++;
cc = i + 'a';
}
m[i] /= 2;
cnt += m[i];
}
if (flag > 1 || get_num(cnt) < n) {
printf("XXX\n");
continue;
}
int res = 0;
while (res != cnt) {
for (int i = 0; i < 26; i++) {
if (m[i]) {
m[i]--;
long long temp = get_num(cnt - res - 1);
m[i]++;
if (n <= temp) {
ans[res++] = 'a' + i;
m[i]--;
break;
}
else
n -= temp;
}
}
}
for (int i = 0; i < res; i++)
printf("%c", ans[i]);
if (flag)
printf("%c", cc);
for (int i = res - 1; i >= 0; i--)
printf("%c", ans[i]);
printf("\n");
}
return 0;
}