题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5651
题意:给出一个字符串,可以打乱字符串的顺序,问可以有多少种方法使其成为回文串。
思路:先判断一下是否有奇数数量的字符,奇数长度的字符串最多有一个,偶数长度不能有奇数数量的字符。
然后我们去考虑半边的字符排列,也就是将所有的字符个数除2,然后在一半的位置上去求组合数相乘。
比如现在有4种字符,一共为a+b+c+d个。先去放第一个有C(a+b+c+d,a)种放法,继续放第二个,有C(b+c+d,b)....所有的数乘起来化简就是(a+b+c+d)!/a!/b!/c!/d!。取模除法可以转换为求逆元来解决,如果是模一个素数x,那么a的逆元为a^(x-2)。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 1000000007
char str[1009];
int T;
int t[30];
LL f[509];
void init()
{
f[0] = 1;
rep(i,1,500) f[i] = (i*f[i-1])%mod;
}
LL Pow( LL a , int b ) // a^b
{
LL ans = 1;
LL temp = a;
while( b )
{
if ( b & 1 ) ans = ( ans * temp )% mod;
temp = ( temp * temp )% mod;
b>>=1;
}
return ans;
}
int main()
{
init();
cin>>T;
getchar();
while(T--)
{
gets(str);
int len = strlen(str);
Clean(t,0);
rep(i,0,len-1) t[ str[i]-'a' ]++;
int n = 0;
int x = 0;
rep(i,0,25)
if ( t[i] > 0 )
{
n+=t[i]/2;
if ( t[i] & 1 ) x++;
}
if ( ( len & 1 && x > 1 ) || ( !(len & 1) && x > 0 ) )
{
puts("0");
continue;
}
LL ans = f[n];
rep(i,0,25)
{
if ( t[i] > 1 )
ans = ( ans * Pow( f[ t[i]/2 ] , mod-2 ) )% mod;
}
cout<<ans<<endl;
}
return 0;
}