判断一个字符串有多少种排列方式使得其为回文字串
很明显,这个字串中最多只能有一种奇数个的字符,且这个奇数个的字符有一个要放在正中间
然后就可以把回文串分为前半段和后半段
前半段与后半段对称,只要求前半段的排列数就好了
设前半段有n个字符,有i种字符,每种字符有m1, m2, m3, ..., mi个
则答案为 n!/(m1! * m2!*m3! * ... * mi!)
这里要用到乘法逆元
#include <iostream>
#include <algorithm>
#include <cstring>
#include <functional>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 1005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int NIL = -1;
char str[MAXN];
const ll mod = 1000000007;
ll num[128];
ll arr[MAXN];
ll extgcd(ll a, ll b, ll &x, ll &y)
{
if (b == 0)
{
x = 1, y = 0;
return a;
}
ll xx, yy;
ll ret = extgcd(b, a % b, xx, yy);
x = yy;
y = xx - (a / b) * yy;
return ret;
}
ll inv(ll a)
{
ll x, y;
ll g = extgcd(a, mod, x, y);
if (g % 1 == 0)
{
x *= 1 / g;
ll t = mod / g;
if (t < 0)
t = -t;
x = (x % t + t) % t;
if (x == 0)
x += t;
return x;
}
else
return NIL;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);
arr[0] = 1;
for (ll i = 1; i < MAXN; ++i)
arr[i] = (arr[i - 1] * i) % mod;
int T;
cin >> T;
while (T--)
{
memset(num, 0, sizeof(num));
cin >> str;
for (int i = 0; str[i]; ++i)
++num[str[i]];
int flag = 0;
for (char ch = 'a'; ch <= 'z'; ++ch)
if (num[ch] & 1)
{
++flag;
--num[ch];
}
if (flag > 1)
{
cout << 0 << endl;
continue;
}
int n = strlen(str) / 2;
ll ans = arr[n];
for (char ch = 'a'; ch <= 'z'; ++ch)
if (num[ch] > 0)
ans = (ans * inv(arr[num[ch] / 2])) % mod;
cout << ans << endl;
}
return 0;
}