[HDU5651.xiaoxin juju needs help(http://acm.hdu.edu.cn/showproblem.php?pid=5651)
xiaoxin巨从小就喜欢字符串,六年级的时候他就知道了什么是回文串。这时,xiaoxin巨说到:如果一个字符串 SS 是回文串,那么该字符串从前往后看和从后往前看是一样一样的。
六年级的暑假,xiaoxin很快就做完了暑假作业,然后到腾讯做起了实习生。这日,leader给了xiaoxin一个字符串,请xiaoxin帮忙写一个函数来生成所有可能的回文串,可以任意改变字符串的顺序但是不可以扔掉某个字符。并且leader告诉xiaoxin,每生成一个不一样的回文串就可以得到一颗西瓜糖。
请你帮忙计算xiaoxin的leader最多需要买多少颗西瓜糖呢?
输入描述
多组测试数据。第一行包含一个整数 T(T\leq 20)T(T≤20) 表示组数。每组测试数据给出一个只包含小写字母的字符串 S(1\leq length(S)\leq 1,000)S(1≤length(S)≤1,000)
输出描述
对于每组测试数据,输出一个数, 表示leader需要买的西瓜糖的个数,结果对 1,000,000,0071,000,000,007 取模。
输入样例
3
aa
aabb
a
输出样例
1
2
1
解题思路
首先统计一下各个字符出现的次数,若出现奇数次的数字大于一个那就直接输出0,否则则将统计的次数/2的数相加,也就是统计回文串的前一半的字母总个数记为
m
,将每个元素重复的次数分别记为
但是因为这个数字非常的大同时要取模,所以要用到欧几里德算法求逆元,这个方法等会儿写个博客链接过去。
逆元:
若, b∗b1%c==1
则, b1 称为 b 模
所以有 (a/b)%c==(a∗b1)%c
根据这个式子,我们可以得到
得到这个式子就好处理了,只要预先处理出 n! 数组,然后将 M! 和 (n1!∗n!!∗⋯∗ni!) 分别算出来,在算出 Ni (分母的逆元)就能得到最后答案了。
代码
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
#define MOD 1000000007
long long x, y, rev;
LL extend_Euclid(LL a, LL b)
{
if (b == 0)
{
x = 1;
y = 0;
} else {
extend_Euclid(b, a % b);
int t = x;
x = y;
y = t - a / b * y;
}
return x;
}
int main() {
int tt, len;
char str[1050];
long long ansa[1000] = {1, 1};
for (int i = 2; i < 1000; i++) {
ansa[i] = ansa[i - 1] * i;
ansa[i] %= 1000000007;
}
scanf("%d", &tt);
while (tt--) {
LL dd = 1;
int c[200] = {0};
scanf("%s", str);
int ou = 0, ji = 0;
LL ans;
len = strlen(str);
for (int i = 0; i < len; ++i) {
c[str[i]]++;
//printf("%d\n",c[str[i]]);
}
for (int i = 0; i < 200; i++) {
if (c[i]) {
if (c[i] % 2) {ji++;}
dd *= (ansa[c[i] / 2]);
dd %= MOD;
ou += c[i] / 2;
//printf("%c%dou:%d,ansa%I64d,dd%I64d\n",i,c[i],ou,ansa[c[i] / 2]);
}
}
if (ji > 1)ans = 0;
else {
ans = ansa[ou];
}
LL ni = extend_Euclid(dd, MOD);
ni = (ni % MOD + MOD) % MOD;
printf("%I64d\n",(ans * ni % MOD));
}
return 0;
}