您的位置:首页 > 其它

【排列组合】HDU5651xiaoxin juju needs help

2016-04-17 00:05 183 查看
题目链接: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


科普一下数论的知识:http://book.2cto.com/201210/5668.html

定理2.4.2 设S是多重集合,它有k种不同类型的对象,且每一种类型的有限重复数分别是n1,n2,…,nk。设S的大小为n=n1+n2+…+nk。则S的排列数目等于



 

证明 给定多重集合S,它有k种类型对象,比如说a1,a2,…,ak,且重复数分别是n1,n2,…,nk,对象总数n=n1+n2+…+nk。我们想要这n个对象的排列数量。可以这样考虑这个问题。一共有n个位置,而我们想要在每一个位置放置S中的一个对象。首先,我们确定放置a1的位置。因为在S中a1的数量是n1,因此必须从n个位置的集合中取出n1个位置的子集。

代码:

#include<iostream>
#include<cstring>
#include<string>
#define LL long long
#define mod 1000000007
using namespace std;
// 排列组合公式:c(n,m)=c(n-1,m)+c(n-1,m-1);
LL c[1010][1010]; // 记录c(n,m);
int a[300]; // 记录每个字符出现的次数;
// 可重复集合的排列数;
void init()
{
for(int i=0;i<=1000;i++){
c[i][0]=c[i][i]=1;
}
for(int i=1;i<=1000;i++){
for(int j=1;j<=i-1;j++){ // j小于等于i;
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
}
int main()
{
int t;
init();
cin>>t;
string s;
while(t--){
cin>>s;
memset(a,0,sizeof(a));
for(int i=0;i<s.size();i++){
a[s[i]]++;
}
int cnt=0;
for(int i=0;i<256;i++){ // ASCII码;
if(a[i]&1) cnt++; // 记录出现次数为奇数的个数;
}
if(cnt==(s.size()&1)){ // 如果长度为奇数的话,那么允许出现一个字符出现的次数为奇数,否则则不允许;
int sum=s.size()/2; // 选一半作为可重复集合的排列问题;
LL ans=1;
for(int i=0;i<256;i++){
ans=ans*c[sum][a[i]/2]%mod; // 对于a[i]/2个字符i在总共sum个位置中可以填的方案数;
sum-=a[i]/2;
}
cout<<ans<<endl;
}else cout<<'0'<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: