题目大意:给出一个字符串,将这个字符串的每个字符进行排列组合后,按字典序,输出第N个回文字符串

解题思路:要输出第N个字符串,首先要先判断是否能组成回文字符串,判断能否组成回文字符串的条件是,字符串中的每个字符的数量为奇数个的不能大于1。

然后进行排列组合,因为是回文字符串,所以两边是对称的,所以只需将左边的字符串求出来,然后按照对称性,就能得到右边的,

要求第N个回文字符串,我们先确定第一个字符(按字典序),然后求出在确定了一个字符的情况下有多少种的回文排列组合,如果该数量小于N,那么就用N-这种情况下的能组成回文数量,再换下一个字符来当第一个字符。

如果所有的情况都枚举完了,数量还小于N的话,那么就表示这个字符串的回文字符串数量<N,输出XXX

如果数量大于N的话,就表示这个字符能填在这个位置,然后再依次递归去求下一个位置的字符,直到能填充的字符数量为0,注意字符串中有一个字符数量为奇数的情况,这个数量为奇数的字符一定是放在最中间的,这样才能构成一个回文字符串

这里有一种特殊情况,是1个字符的情况,单个字符构成回文字符串,所以N>1的话,就会输出XXX


#include<cstdio>
#include<cstring>

char str[50];
long long N;
int sign, c[30];

long long A(int num) {
	long long ans = 1;
	for(int i = 2; i <= num; i++)
		ans *= i;
	return ans;
}

long long COUNT(int num) {

	long long ans = 1;
	while(num) {
		ans *= num;
		num--;
	}
	for(int i = 1; i <= 26; i++)
		if(c[i])
			ans /= A(c[i]);
	return ans;
}

void dfs(int num, long long move) {
	if(num == 0) {
		if(move > 1)  
			printf("XXX");	
		else if(sign)
			printf("%c",sign + 'a' - 1);
		return ;
	}

	for(int i = 1; i <= 26; i++) {
		if(c[i]) {	
			c[i]--;
			long long ans = COUNT( num - 1);
			if(ans < move)
				move -= ans;
			else {
				printf("%c", i + 'a' - 1);
				dfs(num-1,move);
				printf("%c", i + 'a' - 1);	
				return ;
			}
			c[i]++;
		}
	}
	printf("XXX");
}

void judge() {

	memset(c,0,sizeof(c));
	int dif, cnt;
	for(int i = 0; str[i]; i++)
		c[str[i]-'a'+1]++;

	dif = cnt = sign = 0;

	for(int i = 1; i <= 26; i++) 
		if(c[i] % 2) {
			sign = i;
			dif++;
		}

	if(dif > 1) {
		printf("XXX");
		return ;	
	}

	for(int i = 1; i <= 26; i++) {
		c[i] /= 2;
		cnt += c[i];	
	}
	dfs(cnt,N);
}
int main() {
	int test,mark = 1;
	scanf("%d",&test);
	while(test--) {
		printf("Case %d: ",mark++);
		scanf("%s%lld",str,&N);
		judge();
		printf("\n");
	}
	return 0;
}