您的位置:首页 > 其它

hdu 5651 组合数学+费马小定理求逆元

2016-04-22 13:24 323 查看
http://acm.hdu.edu.cn/showproblem.php?pid=5651

给定字符串,判断任意交换顺序,能产生几个回文串。

先判定0,如果有超过一个字母出现的次数那么就是不可能的。

求个数就是用排列组合了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1009
typedef long long ll;
char s[M];
int num[26];
const int mod = 1000000007;
ll qpow(ll x,ll n,ll mod)
{
ll ans = 1;
while(n)
{
if(n & 1) ans = ans * x % mod;
x = x * x % mod;
n >>= 1;
}
return ans;
}
ll C(ll a,ll b)
{
ll s1 = 1, s2 = 1;
for(int i = b - a + 1;i <= b;i++) s1 = s1*i%mod;
for(int i = 1;i <= a;i++) s2 = s2*i%mod;
ll inv = qpow(s2,mod-2,mod);
return s1*inv%mod;
//return (s1%(s2*mod))/s2;
}
int main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--)
{
cin >> s;
memset(num,0,sizeof(num));
int len = strlen(s);
for(int i = 0;i < len;i++) num[s[i] - 'a']++;
int sum = 0;
for(int i = 0;i < 26;i++)
{
if(num[i]&1) sum++;
}
if(sum > 1)
{
cout << 0 << endl;
continue;
}
ll ans = 1;
sum = len/2; //只看左半边
for(int i = 0;i < 26;i++)
{
if(!num[i]) continue;
if(num[i] & 1) num[i]--;
ans = ans*C(num[i]/2,sum)%mod;
sum -= num[i]/2; //已经放过的位置要减掉
}
cout << ans << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: