HDU5651 (xiaoxin juju needs help)
题意:给出一个字符串,问将该字符串的所有字符任意组合,问能有多少种组合方式使得字符串回文。
思路:
既然要求个数,那就有必要统计每个字符出现的次数(0 ~127)
然后就很容易发现当一个字符串中有两个或两个以上的元素个数为奇数,就构不成回文
将能构成回文的串平分成两份(或者有一个多一个),将这一半全排列再取模就是答案了—–(这里用逆元处理,加暴力即可)
有必要列下全排列公式:
——————————————————————————
–> M!/(M1!M2!…*Mn!)
M : tot /2
Mn: each/2
——————————————————————————
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const ll maxn = 1000 + 5;
const ll mod = 1000000007;
char ss[maxn];//save the string
ll aa[129]; //save the num after calculate
ll bb[maxn];//save the jiecheng from the array aa;
//dabiao
ll qmod(ll x){
if(0==x)return 1;
ll ss = 1;
for(int i = 1; i <= x; i++){
ss = ss * i % mod;
}
return ss;
}
//此处照搬模板,有更清楚的模板,总结中可见
//该模板求出的逆元可能为负,所以要加mod加到正为止
ll ExtEnclid(ll d,ll f) //d: return d^-1 f:mod
{
ll x1,x2,x3,y1,y2,y3,t1,t2,t3,k;
if(d>f) d=d+f-(d=f); //交换d和f使得d<f
x1=1,x2=0,x3=f;
y1=0,y2=1,y3=d;
while(1)
{
if(y3==0) return 0; //没有逆元,gcd(d,f)=x3
if(y3==1) return y2;//逆元为y2,gcd(d,f)=1
k=x3/y3;
t1=x1-k*y1, t2=x2-k*y2, t3=x3-k*y3;
x1=y1,x2=y2,x3=y3;
y1=t1,y2=t2,y3=t3;
}
}
ll GetFenzi(ll n){
ll dd = 1;
for (int i = 0; i < n; i++){
if(bb[i] == 0) dd = dd;
else{
for(int s = 1; s <= bb[i]; s++){
dd = dd*s%mod;
}
}
}
return ExtEnclid(dd, mod);
}
int main()
{
int T;
scanf("%d", &T);
while (T--){
memset(ss,0,sizeof(ss));
memset(aa,0,sizeof(aa));
memset(bb,0,sizeof(bb));
scanf("%s", ss);
int len = strlen(ss);
int j = 0;
int cal = 0, flag = 0;
for (int i = 0; i < len; i++){
int mm = ss[i];
aa[mm]++;
}
for (int i = 0; i < 129; i++){
if(aa[i] > 0){
if(aa[i]%2) bb[j++] = ((aa[i]-1)/2);
else bb[j++] = (aa[i]/2);
}
if(aa[i] % 2){
cal++;
if(cal >= 2){
flag = 1;
break;
}
}
}
if (flag) printf("0\n");
else{
ll ny = GetFenzi(j);
while(ny < 0){
ny+=mod;
}
ll tot = qmod(len/2);
ll res = tot*ny%mod;
printf("%I64d\n",res);
}
}
return 0;
}
注意:要使用long long 类型