UVa 11027

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=115&page=show_problem&problem=1968


题目大意是,给你一串字符串,输出它的字典序的第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] != ''; ++i)
 28         ++num[str[i] - 'a'];
 29 
 30     int OddNum = 0;
 31 
 32     for(int i = 0; i < 26; ++ i)
 33     {
 34         if(num[i] & 1)
 35         {
 36             ++OddNum;
 37             OddChar = i + 'a';
 38         }
 39 
 40         num[i] >>= 1;
 41     }
 42 
 43     if(OddNum > 1)
 44         return 0LL;
 45 
 46     if(OddNum == 0)
 47         OddChar = '#';
 48 
 49     len = strlen(str) >> 1;
 50     return Permutation(len);
 51 }
 52 
 53 void solve(LL x, int n)
 54 {
 55     for(int i = 0; i < len; ++ i)
 56         for(int j = 0; j < 26; ++ j)
 57             if(num[j])
 58             {
 59                 --num[j];
 60                 LL tmp = Permutation(n - 1 - i);
 61 
 62                 if(tmp < x)
 63                 {
 64                     ++num[j];
 65                     x -= tmp;
 66                     continue;
 67                 }
 68 
 69                 ans[i] = j + 'a';
 70                 break;
 71             }
 72 }
 73 
 74 /*
 75 void dfs(int cur, int n, LL x)
 76 {
 77     if(n == 0)
 78         return;
 79 
 80     for(int i = 0; i < 26; ++ i)
 81         if(num[i])
 82         {
 83             --num[i];
 84             LL tmp = Permutation(n - 1);
 85 
 86             if(tmp < x)
 87             {
 88                 ++num[i];
 89                 x -= tmp;
 90                 continue;
 91             }
 92 
 93             ans[cur] = i + 'a';
 94             dfs(cur + 1, n - 1, x);
 95         }
 96 }*/
 97 
 98 int main()
 99 {
100     int T;
101     scanf("%d", &T);
102     fact[0] = 1;
103 
104     for(int i = 1; i < 16; ++ i)
105         fact[i] = fact[i - 1] * i;
106 
107     for(int tCase = 1; tCase <= T; ++ tCase)
108     {
109         scanf("%s%d", str, &n);
110         printf("Case %d: ", tCase);
111         LL MaxNumber = MaxPalindromic();
112 
113         if(MaxNumber < n)
114             puts("XXX");
115         else
116         {
117             //dfs(0, len, n);
118             solve(n, len);
119 
120             for(int i = 0; i < len; ++ i)
121                 putchar(ans[i]);
122 
123             if(OddChar != '#')
124                 putchar(OddChar);
125 
126             for(int i = len - 1; i >= 0; -- i)
127                 putchar(ans[i]);
128 
129             putchar('
');
130         }
131     }
132 
133     return 0;
134 }
View Code
原文地址:https://www.cnblogs.com/tank39/p/3911400.html