题目大意是,给你一串字符串,输出它的字典序的第n个回文字符串。如果没有或者没有n这么大的就输出“XXX”。
首先先考虑能不能构成回文串,首先奇数个的字母肯定只能有1个,不然肯定不能没办法构成回文串。然后要得到一个回文串,只需要算出(strlen(str)>> 1)这么长的字符串就行了,然后看看是否存在个数为奇数的字母,最后把算出来的字符串反向输出一下就OK了。
本来是打算用康托展开的,后来考虑到重复的元素是否能将重复的字母看成不重复的来算,最后花了一个下午,得出结论,不行。
最后百度了下,看了题解,原来要用搜索来做。
首先先计算一下所有的字母的个数,然后每个字母的个数直接除以2,用这个计算字符串的总排列数。接下来就直接搜索每一位,比如说对于第一位,先取出字典序最小的字母,计算第一个位置为这个字母的情况下又多少种排列数,比如说是k,如果k >= n,那么这个位置就可以确定下来了,如果k < n,, 那么这个位置放这个字母显然是不够的,需要放更大的字典序的字母进来,在继续找之前还要进行一步操作, n -= k, 因为如果对一个字符串进行全排列,肯定先排完第一个位置放字典序为最小的字母,然后才开始字典序第二大的。一直这样进行下去,这个字符串就搜索出来了。在这里写了个递归的代码,后来又改成了非递归的。
上代码:
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 typedef long long LL; 5 const int MAXN = 30 + 5; 6 7 LL fact[16]; 8 char OddChar; 9 int n, len, num[26]; 10 char str[MAXN], ans[MAXN]; 11 12 //计算有多少种 13 LL Permutation(int len) 14 { 15 LL res = fact[len]; 16 17 for(int i = 0; i < 26; ++i) 18 res /= fact[num[i]]; 19 20 return res; 21 } 22 23 LL MaxPalindromic() 24 { 25 memset(num, 0, sizeof(num)); 26 27 for(int i = 0; str[i] != '