题目意思为解码字符串,要输出第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 }