您的位置:首页 > 其它

HDU xiaoxin juju needs help (逆元+排列组合)

2016-03-29 00:17 393 查看
转载地址:http://blog.csdn.net/saber_acher/article/details/50994112

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

题意:给你遗传由若干个小写字母组成的字符串,你可以任意变动互相之间的位子,但不能删除或添加元素,问可以组成多少种不同回文串。思路:很简单的排列组合,太简单我就不把他分到排列组合里去了。先判断是否可以组成回文串,如果有一个以上的奇数个同一的字母,则无论如何都不会组成回文串。剩下的就枚举回文串的一边,所有的元素都取半。所有元素的一半的和的阶乘除于每个元素一半的的阶乘即是答案。这就是问题的所在,除于之后是要取模的。除法取模问题当然是逆元了,谈到逆元当然是费马小定理喽。费马小定理:费马小定理(Fermat
Theory)是数论中的一个重要定理,其内容为:
假如p是质数,且(a,p)=1,那么
a(p-1)≡1(mod
p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
#include<stdio.h>
#include<string.h>
const int maxn=1111;
int num[maxn];
char s[maxn];
typedef long long ll;
const int mod=1e9+7;
ll f[maxn];
void init()
{
f[0]=1;
f[1]=1;
for(int i=2;i<maxn;i++)
f[i]=f[i-1]*i%mod;
}
ll cal(ll x)
{
ll res=1;
int k=mod-2;
while(k)
{
if(k&1)
{
res*=x;
res%=mod;
}

x*=x;
x%=mod;
k>>=1;
}
return res;
}
int main()
{
int T;
init();
while(scanf("%d",&T)!=EOF)
while(T--)
{
scanf("%s",s);
int n=strlen(s);
memset(num,0,sizeof(num));
for(int i=0;i<n;i++)
num[s[i]-'a']++;
int len=0;
for(int i=0;i<26;i++)
if(num[i]%2)
len++;
if(len>1)
{
printf("0\n");
continue;
}
int total=0;
for(int i=0;i<26;i++)
{
num[i]/=2;
total+=num[i];
}
ll res=f[total];
for(int i=0;i<26;i++)
if(num[i])
{
res=res*cal(f[num[i]])%mod;
}
printf("%lld\n",res);
}
return 0;
}


too difficult!!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: