UVA 11027 - Palindromic Permutation

  题目意思为解码字符串,要输出第n个回文字符串,因为对称关系,前一半确定了,后一半也就跟着确定了,所以n其实就是前一半字符串的编码,还要减去1,直接解码出来再复制给后半即可

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 
  5 using namespace std;
  6 
  7 typedef long long ll;
  8 
  9 int T,a[26],st[26],cas=1,len;
 10 ll n;
 11 char s[50];
 12 
 13 ll fa(int &x)//阶乘
 14 {
 15     ll res=1;
 16     for(int i=2;i<=x;i++)
 17         res*=i;
 18     return res;
 19 }
 20 
 21 ll f(int*st)//种数
 22 {
 23     ll x=1,y=1;
 24     int sum=0;
 25     for(int i=0;i<26;i++)
 26     {
 27         if(st[i]>1) y*=fa(st[i]);
 28         sum+=st[i];
 29     }
 30     x=fa(sum);
 31     return x/y;
 32 }
 33 
 34 ll code(char*s,int *st)//编码,这里没用到,开始理解错题意,以为是大于给出字符串的第n个回文字符串,打了一大堆才发现理解错题意了,main函数中的已删除,编码的就留着
 35 {
 36     ll x=0;
 37     for(int i=0;i<len>>1;i++)
 38     {
 39         int cnt=0;
 40         st[s[i]-'a']--;
 41         for(int j=i+1;j<len>>1;j++) if(s[j]<s[i]) cnt++;
 42         x+=cnt*f(st);
 43     }
 44     return x;
 45 }
 46 
 47 void decode(ll &goal,int*st)//解码
 48 {
 49     int l=len>>1;
 50     for(int i=0;i<l;i++)
 51     {
 52             ll x=0;
 53         for(int j=0;j<26;j++)
 54         {
 55             if(!st[j]) continue;
 56             st[j]--;
 57             ll y=f(st);
 58             x+=y;
 59             if(goal<x)//比如a开头的有6种,b开头的有3种,要找第八种,则应该是b开头的
 60             {
 61                 s[i]=j+'a';
 62                 goal-=x-y;
 63                 break;
 64             }
 65             else st[j]++;
 66         }
 67     }
 68 }
 69 
 70 int main()
 71 {
 72     scanf("%d",&T);
 73     while(T--)
 74     {
 75         scanf("%s%lld",s,&n);
 76         printf("Case %d: ",cas++);
 77         memset(a,0,sizeof(a));
 78         int i,x;
 79         len=strlen(s);
 80         for(i=0;i<len;i++)
 81             a[s[i]-'a']++;
 82         i=0;
 83         if(len&1)
 84         {
 85             for(;i<26;i++)
 86             {
 87                 if(a[i]&1)
 88                 {
 89                     a[i]>>=1;
 90                     x=i;//x记下长度为奇数时中间那个
 91                     break;
 92                 }
 93                 a[i]>>=1;
 94             }
 95             i++;
 96         }
 97         for(;i<26;i++)
 98         {
 99             if(a[i]&1) break;
100             a[i]>>=1;
101         }
102         if(i<26)
103         {
104             puts("XXX");
105             continue;
106         }
107                 ll goal,all;//最大可能是(30/2)!,超出了int范围,要用ll
108         all=f(a);
109         goal=n-1;
110         if(goal>=all) strcpy(s,"XXX");
111         else
112                 {
113                         decode(goal,a);
114                         for(int i=0;i<len>>1;i++)
115                                 s[len-i-1]=s[i];
116                         if(len&1) s[len>>1]=x+'a';
117                 }
118                 puts(s);
119     }
120     return 0;
121 }
View Code

 

转载于:https://www.cnblogs.com/cdyboke/p/4855938.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值