【HDOJ 5652】xiaoxin juju needs help(排列组合)

【HDOJ 5652】xiaoxin juju needs help(排列组合)

xiaoxin juju needs help

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1122    Accepted Submission(s): 322



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

Sample Input
  
  
3 aa aabb a
 

Sample Output
  
  
1 2 1
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5650  5649  5648  5646  5645 
 

Statistic |  Submit |  Discuss | Note


题目大意:T组输入,每组一个字符串。只由小写字母组成。

要求通过交换该串中某些字符的位置,让它变成一个回文串。问可以得到多少种不同的回文串。


题目拐了个弯。其实就是问给一些字符,用它们能组成多少种不同的字符串……

首先可以知道,如果每种字符都是偶数个,一定可以组成回文串(对称放)

如果有奇数个,奇数个的字符只能有一种,否则无法构成回文串(奇数的字符放到中心,这样剩下的由全变成偶数了,关于这个奇数字符中心对称就是。


接下来就是对于能组成回文串的字符进行放置。

我的方法是用组合数。

只放一半的字符,另一半对称即可。

如果总长度len 那么需要放置的就是len/2个字符。

这样枚举每种字符 假设m为放置的字符个数(len/2) vi表示第i种字符数量的一半(如上,只放一半,另一半对称)

结果就是C(m,v1)*C(m-v1,v2)*C(m-v1-v2,v3)*...*C(v26,v26)


递推搞一下就出来了。组合数可以递归预处理出来。


另一种直接用定理,。

如果每个字符都当做不一样的话,总的组合就是n!(n为字符个数

然后出去重复,就是n!/v1!/v2!/v3!/..../v26!


除阶乘没法取余,会炸,反过来求逆元即可,同样可以预处理出来。


逆元的没写,上下组合的吧:

#include <iostream>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <list>
#include <algorithm>
#include <map>
#include <set>
#define LL long long
#define Pr pair<int,int>
#define fread() freopen("in.in","r",stdin)
#define fwrite() freopen("out.out","w",stdout)

using namespace std;
const int INF = 0x3f3f3f3f;
const int msz = 10000;
const int mod = 1e9+7;
const double eps = 1e-8;

int cnt[26];

LL C[555][555];

LL cal(int m,int n)
{
	if(~C[m][n]) return C[m][n];
	if(m == n) return C[m][n] = 1;
	if(n == 0) return C[m][n] = 1;
	if(m == 0) return C[m][n] = 0;
	return C[m][n] = (cal(m-1,n)+cal(m-1,n-1))%mod;
}

int main()
{
	//fread();
	//fwrite();

	memset(C,-1,sizeof(C));

	for(int i = 500; i >= 0; --i)
		for(int j = 500; j >= 0; --j)
			if(C[i][j] == -1) cal(i,j);

	int t;
	char ch;
	scanf("%d",&t);
	getchar();
	while(t--)
	{
		memset(cnt,0,sizeof(cnt));
		while((ch = getchar()) != '\n' && ch != '\r') cnt[ch-'a']++;
		int c = 0,len = 0;
		for(int i = 0; i < 26; ++i)
		{
			if(cnt[i]&1) c++;
			len += cnt[i];
		}
		
		if(c > 1)
		{
			puts("0");
			continue;
		}

		LL ans = 1;
		len >>= 1;
		for(int i = 0; i < 26; ++i)
		{
			ans = (ans*C[len][cnt[i]>>1])%mod;
			len -= cnt[i]>>1;
		}
		printf("%lld\n",ans);
	}

	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值