题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5651
题目意思我看了半天没读懂,一直以为是回文子串又没看见substring的单词最后看博客才知道是用给出的字符任意组合。
求不同的回文串个数,显然对于一个长度为奇数的串,我们可以枚举中间位置的元素,然后计算由剩余字符对半分(如果不可以就是零)之后的
排列数就好了,由于有重复字符排列数公式也会不同,偶数串的话直接计算一次就好了。
假设串长度为n,有m种不同元素,每种有ai个,则排列数就是 n!/(a1!*a2!*a3!*......am!)
接着讨论具体计算过程,
对于solve(),就是计算在当前合法状态下,对半分之后的排列总数对mod取余,公式就是
len!/(a1!*a2!*a3!......*am!)%mod,由于阶乘值会很大所以只能用同余公式和逆元进行化简,
==> (1%mod*2%mod*....*len%mod)%mod*(1/a1!)%mod*(1/a2!)*......*(1/am!)%mod //我们用fac[i]表示阶乘取模,prv[i]表示i!的逆对mod取模
//对于1/x!%mod<==>1*(1/2)%mod*(1/3)%mod*...(1/x)%mod<==> 2-1%mod*3-1%mod......*x-1%mod
==>fac[i]*prv[a1]*prv[a2]*.....*prv[am]%mod;
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 LL mod=1e9+7; 5 LL a[30]; 6 LL fac[1005]={1}; 7 LL inv[1005]={1,1}; 8 LL prv[1005]={1,1}; 9 LL solve(int len) 10 { 11 int i,j,k; 12 LL res=fac[len]; 13 for(i=0;i<26;++i) 14 { 15 if(a[i]&1) return 0; 16 a[i]/=2; 17 res=res*prv[a[i]]%mod; 18 a[i]*=2; 19 } 20 return res; 21 } 22 int main() 23 { 24 int t,i,j,n,m; 25 char str[1005]; 26 for(LL i=1;i<=1000;++i) fac[i]=fac[i-1]*i%mod; 27 for(i=2;i<=1000;++i) { 28 inv[i]=(mod-mod/i)*inv[mod%i]%mod; 29 prv[i]=prv[i-1]*inv[i]%mod; 30 } 31 cin>>t; 32 while(t--){memset(a,0,sizeof(a)); 33 scanf("%s",str); 34 int len=strlen(str); 35 for(i=0;i<len;++i){ 36 a[str[i]-'a']++; 37 }LL ans=0; 38 if(len&1){ 39 for(i=0;i<26;++i){ 40 if(!a[i]) continue; 41 a[i]--; 42 ans=(ans+solve((len-1)/2))%mod; 43 a[i]++; 44 } 45 } 46 else{ 47 ans=solve(len/2); 48 } 49 cout<<ans<<endl; 50 } 51 return 0; 52 }