【排列组合】HDU5651xiaoxin juju needs help
2016-04-17 00:05
183 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5651
问题描述
输入描述
输出描述
输入样例
输出样例
科普一下数论的知识: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;
}
问题描述
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;
}
相关文章推荐
- 如何根据v$parameter查询Oracle隐含参数
- [Spring]简单Junit和Spring整合配置
- [网络编程]——TCP_Socket通信_聊天室_客户端多线程
- 动态设置listview的高度
- EZchip将推全球首款100核64位ARM A-53芯片
- 二分查找算法
- 杭电acm2015
- 对匿名函数理解
- 二分查找算法
- HDU 5667 :Sequence
- 简单选择排序
- linux 定期备份脚本--优化终结
- HDOJ 2159 FATE
- CSU 1600 Twenty-four point
- google big table
- google file system
- Clinews:从命令行阅读新闻和最新头条
- 刷单将死?淘宝新规严打虚假交易
- orm获取关联表里的属性值
- PHP加密3DES报错 Call to undefined function: mcrypt_module_open() 如何解决