hdu5651 乘法逆元

来源:互联网 发布:淘宝蜜妃儿女模特是谁 编辑:程序博客网 时间:2024/06/08 12:10


判断一个字符串有多少种排列方式使得其为回文字串

很明显,这个字串中最多只能有一种奇数个的字符,且这个奇数个的字符有一个要放在正中间

然后就可以把回文串分为前半段和后半段

前半段与后半段对称,只要求前半段的排列数就好了

设前半段有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;}elsereturn 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;}


原创粉丝点击