回文字符串:
=============Question================
Now that the king knows how to find out whether a given word has an anagram which is a palindrome or not, he is faced with another challenge. He realizes that there can be more than one anagram which are palindromes for a given word. Can you help him find out how many anagrams are possible for a given word which are palindromes?
The king has many words. For each given word, the king needs to find out the number of anagrams of the string which are palindromes. As the number of anagrams can be large, the king needs number of anagrams % (10^9+ 7).
Input format :
A single line which will contain the input string
Output format :
A single line containing the number of anagram strings which are palindrome % (10^9 + 7).
Constraints :
1<=length of string <= 105
Each character of the string is a lowercase alphabet.
Each testcase has atleast 1 anagram which is a palindrome.
Sample Input 01 :
aaabbbb
Sample Output 01 :
3
Explanation :
Three permutation of given string which are palindrome can be given as abbabba , bbaaabb and bababab.
Sample Input 02 :
cdcdcdcdeeeef
Sample Output 02 :
90
=============================
很明显如果字符串中某个字符出现次数为奇数,则该字符必须出现在整个串的中间,才有可能让整个串为回文。如果有两个或超过两个的串为奇数,则整个串必不回文。
既然整个串为回文,我们只需要对称考虑一边字符串的组合数,就可以知道对给定字符串有多少回文组合。
这个问题转化为求回文字符串一侧的组合数,其实是计算
p! / (x! y! z! ... n!)
p为所有不同的字符除以2以后的综合,x,y...,n是每个不同的字符除以2以后的值。
这个数字可能非常大,必须小心溢出,这就是为什么要模1000000007了。即便如此,这个计算该怎么进行呢?
参考http://comeoncodeon.wordpress.com/category/algorithm/提供的算法,可以很方便的计算。
/* This function calculates (a^b)%MOD */
unsigned long long pow(unsigned long long a, unsigned long long b, unsigned long long MOD)
{
unsigned long long x = 1;
if (b == 0) {
return 1;
}
if (b == 1) {
if (a > MOD) {
return a%MOD;
}
return a;
}
x = pow(a, b >> 1, MOD);
x = x*x;
if (x > MOD) {
x %= MOD;
}
if ((b & 0x1) == 1) {
x = x * a;
if (x > MOD) {
x %= MOD;
}
}
return x;
}
/* Modular Multiplicative Inverse
Using Euler's Theorem
a^(phi(m)) = 1 (mod m)
a^(-1) = a^(m-2) (mod m) */
unsigned long long InverseEuler(unsigned long long n, unsigned long long MOD)
{
return pow(n,MOD-2,MOD);
}
unsigned long long factorial(int total, unsigned short count[], int len) {
unsigned long long vec[51];
vec[0] = 1;
for (int i = 1; i < 51; i++) {
vec[i] = (vec[i-1] * i) % PRIME;
}
unsigned long long result = 0;
for (int i = 0; i < len; i++) {
int c = count[i];
if (c != 0) {
if (result == 0) {
result = InverseEuler(vec[c], PRIME);
} else {
result = (InverseEuler(vec[c], PRIME) * result) % PRIME;
}
}
}
return (vec[total] * result) % PRIME;
}
int palindrome(const string& s) {
unsigned short count4allchar[CHAR_NUM];
int i = 0;
for (i = 0; i < CHAR_NUM; i++) {
count4allchar[i]=0;
}
for (string::const_iterator iter = s.begin();
iter != s.end(); iter++) {
char c = *iter;
count4allchar[c - 'a']++;
}
// if there are more than one odd in the string, return 0,
// otherwise, count the number of even number and save the even/2 number back
int oddCount = 0;
int total = 0;
for (i = 0; i < CHAR_NUM; i++) {
int num = count4allchar[i];
if (num != 0) {
if ((num & 0x1) == 1) {
oddCount++;
if (oddCount > 1) {
return 0;
}
}
count4allchar[i] = num >> 1; // div 2
total += count4allchar[i];
}
}
//
int result = factorial(total, count4allchar, CHAR_NUM);
return result;
}