hdu5651xiaoxin juju needs help 乘法的逆元||重复元素的排列

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≤20) which represents the number of test cases.
For each test case, there is a single line containing a string S(1≤length(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,007.

Sample Input

3
aa
aabb
a

Sample Output

1
2
1

Source
BestCoder Round #77 (div.2)

题意:给你N个字符,所有排列中,是回文串的排列有多少个(左右对称)

先看:n个元素的排列,n个元素有p种不同的元素,每种元素的个数分别是a1,a2,a3…ap;
所以排列的总数有两种表示方法
1.fact(n)/(fact(a1)*fact(a2)***fact(ap))
fact(n)为n的阶乘。。
我们得求出fact(a)的逆元。。及a*a^-1=1%mod;这样1/a=a^-1;所以上边的式子可写成fact(a)*fact(a1)^-1*fact(a2)^-1***fact(ap)^-1;

//a的逆元%n
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
    if(a==0&&b==0) return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    long long d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
    long long x,y;
    long long d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}
//预处理出1-500的阶乘的逆元
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long quipow(long long a,long long b)
{
    long long ans=1;
     while(b)
     {
         if(b&1) ans=ans*a%mod;
         b>>=1;
         a=a*a%mod;
     }
     return ans%mod;
}
//fact[i]的的逆元nv[i]
long long fac[505],inv[505];
void prepare()          阶乘逆元
{
    fac[0]=fac[1]=1;
    for(int i=2;i<=500;i++)   fac[i]=fac[i-1]*i%mod;

    inv[500]=quipow(fac[500],mod-2);
    for(int i=500-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}

2.out=c(sum,a1)*c(sum-a1,a2)*c(sum-a1-a2,a3)*c(sum-a1-a2–ap-1,ap);
所以预处理排列组合的结果,,

long long c[1005][1005];
void init()
{
    c[1][1]=1;
    for(int i=0;i<=1000;i++) c[i][0]=c[i][i]=1;
    for(int i=2;i<=1000;i++)
    {
        for(int j=1;j<=i;j++)
        {
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
}

最后贴上三种AC的代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define mod 1000000007

long long fact(int n){
    long long out=1;
    for(int i=1;i<=n;i++) out=out*i%mod;
    return out;
}
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
    if(a==0&&b==0) return -1;//无最大公约数
    if(b==0){x=1;y=0;return a;}
    long long d=extend_gcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
    long long x,y;
    long long d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}

int main()
{
    int T_T;
    scanf("%d",&T_T);
    getchar();
    while(T_T--){
        char a[1005];
        int cnt[100];
        memset(cnt,0,sizeof(cnt));
        gets(a);
        int len=strlen(a);
        for(int i=0;i<len;i++){
            cnt[a[i]-'a'+1]++;
        }

        bool huichuan=true;
        int ji=0;

        long long ans=1;
        for(int i=1;i<=26;i++){
            if(cnt[i]%2!=0){
                if(ji!=0){
                    huichuan=false;
                    break;
                }
                ji++;
            }
            if(cnt[i]>0) ans=ans*mod_reverse(fact(cnt[i]/2),mod)%mod;
        }

        if(huichuan==true){
            printf("%I64d\n",ans*fact(len/2)%mod);
        }
        else printf("0\n");

    }
    return 0;
}
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define mod 1000000007

//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long quipow(long long a,long long b)
{
    long long ans=1;
     while(b)
     {
         if(b&1) ans=ans*a%mod;
         b>>=1;
         a=a*a%mod;
     }
     return ans%mod;
}
//fact[i]的的逆元nv[i]
long long fac[505],inv[505];
void prepare()          //阶乘逆元
{
    fac[0]=fac[1]=1;
    for(int i=2;i<=500;i++)   fac[i]=fac[i-1]*i%mod;

    inv[500]=quipow(fac[500],mod-2);
    for(int i=500-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}

int main()
{
    int T_T;
    scanf("%d",&T_T);
    getchar();
    prepare();
    while(T_T--){
        char a[1005];
        int cnt[100];
        memset(cnt,0,sizeof(cnt));
        gets(a);
        int len=strlen(a);
        for(int i=0;i<len;i++){
            cnt[a[i]-'a'+1]++;
        }

        bool huichuan=true;
        int ji=0;

        long long ans=1;
        for(int i=1;i<=26;i++){
            if(cnt[i]%2!=0){
                if(ji!=0){
                    huichuan=false;
                    break;
                }
                ji++;
            }
            if(cnt[i]>0) ans=ans*inv[cnt[i]/2]%mod;
        }

        if(huichuan==true){
            printf("%I64d\n",ans*fac[len/2]%mod);
        }
        else printf("0\n");
    }
    return 0;
}
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define mod 1000000007
long long c[1005][1005];
void init()
{
    c[1][1]=1;
    for(int i=0;i<=1000;i++) c[i][0]=c[i][i]=1;
    for(int i=2;i<=1000;i++){
        for(int j=1;j<=i;j++){
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
}
int main()
{
    int T_T;
    scanf("%d",&T_T);
    getchar();
    init();
    while(T_T--){
        char a[1005];
        int cnt[100];
        memset(cnt,0,sizeof(cnt));
        gets(a);
        int len=strlen(a);
        for(int i=0;i<len;i++){
            cnt[a[i]-'a'+1]++;
        }
        bool huichuan=true;
        int ji=0;
        long long ans=1;
        for(int i=1;i<=26;i++){
            if(cnt[i]%2!=0){
                if(ji!=0){
                    huichuan=false;
                    break;
                }
                ji++;
            }
            int times=cnt[i]/2;
            ans=ans*c[len/2][times]%mod;
            len=len-cnt[i];
        }
        if(huichuan==true){
            printf("%I64d\n",ans);
        }
        else printf("0\n");
    }
    return 0;
}
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         I have a dream!A AC deram!!
 orz orz orz orz orz orz orz orz orz orz orz
 orz orz orz orz orz orz orz orz orz orz orz
 orz orz orz orz orz orz orz orz orz orz orz

*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值