原题:
http://acm.hdu.edu.cn/showproblem.php?pid=5651
- 很容易看出来的是,如果一个字符串中,多于一个字母出现奇数次,则该字符串无法形成回文串,因为不能删减字母。
- 当能构成回文串时,我们只需考虑这个回文串左半部分的情况,所以这个问题也就变成了求一半字符串的有重复的全排列。
- 因为应用全排列公式中,会用大数除以大数再取余,除法不能简单的分子、分母取余再做除法,这时就要用到乘法逆元,同时用费马小定理求乘法逆元
- 相关公式:http://www.cnblogs.com/i2u9/p/full_seq.html
- 乘法逆元及其证明:http://www.cnblogs.com/tiankonguse/archive/2012/08/14/2638949.html
#include<stdio.h>
#include<string.h>
#define maxn 1111
#define mod 1000000007
char s[maxn];
int book[];//记录每个字母出现次数
long long fact[maxn];//计算保存阶乘
//求快速幂
long long fpow(long long a,long long b){
long long res = ;
while(b){
if(b&)
res = res*a%mod;
b >>= ;
a = a*a%mod;
}
return res;
}
int main(){
//计算阶乘,全排列用
fact[] = ;
for(int i = ;i<maxn;i++)
fact[i] = fact[i-]*i%mod;
int t;
scanf("%d",&t);
while(t--){
memset(book,,sizeof(book));
scanf(" %s",s);
for(int i = ;s[i];i++){
book[s[i]-'a']++;
}
int cnt = ;//计算出现奇数次字母的个数
for(int i= ;i<;i++){
if(book[i]&)
cnt++;
book[i] /= ;
}
int len = strlen(s);
if(cnt >){
puts("");
}else{
long long ans = fact[len/];
for(int i = ;i<;i++)
if(fact[book[i]])
ans = ans*fpow(fact[book[i]],mod-)%mod;
printf("%I64d\n",ans);
}
}
return ;
}
y=n!x1!x2!x3!⋯xk!y=n!x1!x2!x3!⋯xk!y=n!x1!x2!x3!⋯xk!y=n!x1!x2!x3!⋯xk!