【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?
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) .
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
Recommend
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;
}