HDU 5651 xiaoxin juju needs help 逆元

题目链接:

hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5651

bc:http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=682&pid=1002

xiaoxin juju needs help

 
 Accepts: 150
 
 Submissions: 966
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
Problem Description

As we all known, xiaoxin is a brilliant coder. He knew palindromic strings when he was only a six grade student at elementry school.

This summer he was working at Tencent as an intern. One day his leader came to ask xiaoxin for help. His leader gave him a string and he wanted xiaoxin to generate palindromic strings for him. Once xiaoxin generates a different palindromic string, his leader will give him a watermelon candy. The problem is how many candies xiaoxin's leader needs to buy?

Input

This problem has multi test cases. First line contains a single integer T(T\leq 20)T(T20) which represents the number of test cases. For each test case, there is a single line containing a string S(1 \leq length(S) \leq 1,000)S(1length(S)1,000).

Output

For each test case, print an integer which is the number of watermelon candies xiaoxin's leader needs to buy after mod 1,000,000,0071,000,000,007.

Sample Input
3
aa
aabb
a
Sample Output
1
2
1

题解:

1、可行性:

统计每个字母出去的次数,如果有两种即以上字母出现的次数为奇数,则一定不可能排出回文串。

2、统计:

由于回文串左右两边必须相同,所以我们考虑一边就可以了(如果为奇数则正中间一个不管就和偶数情况是一样的了)。

则可以转化为排列组合问题,等价于求解: (cnt[i]代表某个字母出现的次数(cnt[i]>0) )

( )%(1e9+7)

由于涉及到除法,要求逆元:

例子:

  求a/b(mod n) 如果b与n互质,则求满足bx=1(%n)的一个解x,原式可转化为a/b*bx(%n),即a*x(%n);这样就把除法消除了。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int maxn = 1000 + 10;
const int mod = 1e9 + 7;
typedef long long LL;

char str[maxn];
int n;

int cnt[33];
int tmp[33], tot;

LL b[maxn];
//预处理出阶乘
void pre() {
    b[0] = b[1] = 1;
    for (int i = 2; i < maxn; i++) b[i] = (b[i - 1] * i) % mod;
}
//扩展的欧几里得算法求逆元
void gcd(LL a, LL b, LL &d, LL &x, LL &y) {
    if (!b) {
        d = a;
        x = 1; y = 0;
    }
    else {
        gcd(b, a%b, d, y, x);//y=x',x=y';
        //x=y'; y=x'-(a/b)*y';
        y -= (a / b)*x;
    }
}

void init() {
    tot = 0;
    memset(cnt, 0, sizeof(cnt));
}

int main() {
    pre();
    int tc;
    scanf("%d", &tc);
    while (tc--) {
        init();
        scanf("%s", str);
        n = strlen(str);
        for (int i = 0; i < strlen(str); i++) {
            cnt[str[i] - 'a']++;
        }
        int flag = 0;
        for (int i = 0; i < 33; i++) {
            if (cnt[i] % 2) flag++;
            //统计一半的字母出现的次数
            if (cnt[i] > 0) {
                tmp[tot++] = cnt[i] / 2;
            }
        }
        if (flag > 1) { printf("0\n"); continue; }
        LL sum = 1;
        for (int i = 0; i < tot; i++) {
            int t = tmp[i];
            sum = (sum*b[t]) % mod;
        }
        LL d, x, y;
        gcd(sum, mod, d, x, y);
        //x有可能是负数,需要处理成正的。
        x = (x%mod + mod) % mod;
        LL ans = (b[n / 2] * x) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}
View Code

 

posted @ 2016-03-27 23:15  fenicnn  阅读(274)  评论(0编辑  收藏  举报