题意:给一个字符串,把它的所有回文串按字典序排序,然后给了个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;
}