P3681 回文
时间限制 :
- MS
空间限制 :
65536 KB
评测说明 : 时限1000ms
问题描述
给你一个由N个小写字母构成的字符串,请你将它改成“回文串”。你可以任意调整串中字符的位置,但不可以删掉其中的字符。问,最多能得到多少个不同的回文串?
结果可能很大,mod 1,000,000,007 后再输出!
例如给出字符串“aabb”
我们通过调整能得到两个回文串,分别是“abba”和”baab”
输入格式
一行,一个字符串
输出格式
一个整数,表示所求答案
样例输入
aabb
样例输出
2
提示
1<=N<=2000
注意到mod对于除法没有分配律,要使用乘法逆元
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define mod 1000000007
using namespace std;
long long cnt[30];
long long f[1000005];
long long niyuan[1000005];
long long supergcd(long long a,long long b,long long &x,long long &y){
long long temp,r;
if(b==0){x=1;y=0;return a;}
r=supergcd(b,a%b,x,y);
temp=x;x=y;y=temp-a/b*y;
return r;
}
long long ni(long long a,long long n)
{
long long x,y;
if(supergcd(a,n,x,y)==1)return (x+n)%n;else return -1;
}
int main(){
string s;
cin>>s;
long long t,len,i,odd=0,l=0,ans;
len=s.length();
for(i=0;i<len;i++){
t=int(s[i])-int('a')+1;
cnt[t]++;
}
for(i=1;i<=26;i++){
if(cnt[i]&1)odd++;
cnt[i]=cnt[i]>>1;
l=l+cnt[i];
}
if(odd>1){
cout<<"0";return 0;
}
f[0]=1;
for(i=1;i<=l;i++)f[i]=f[i-1]*i%mod;
for(i=1;i<=l;i++){
niyuan[i]=ni(f[i],mod);
}
ans=f[l];`
for(i=1;i<=26;i++){
if(cnt[i]==0)continue;
ans=(ans*niyuan[cnt[i]])%mod;
}
cout<<ans%mod;
}
Solution 2 by spark
分析:
将所给字符串中i号字母出现的次数为cnt[i](a是1号);
(1)如果出现了奇数次的字母多于一个,那么一定无解。
(2)如果有解,对于回文串的一半而言,每个字母出现了 cnt[i]/2次,总长度是T=n/2。
那么方案书就是这些字母的组合方案数,由排列组合知识得:
ANS= T! / (cnt[1]/2)!/(cnt[2]/2)!/(cnt[3]/2)!/....../(cnt[26]/2)! (cnt[i]!=0)
但是这样早就超过了long long,由于求的是模余系下后的结果,所以除运算可以用乘法逆元来解决。
求乘法逆元的方法有两种:
扩欧和费马小定理(注意题目中的1000000007是一个质数)
以下用的是费马小定理的方法:
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const LL maxn=2000+5 ,mod=1000000007 ;
char s[maxn];
LL f[maxn],cnt[30],r[maxn];
LL power_mod(LL a,LL b,LL t){
LL ans=1;
for(a%=t;b;a=a*a%t,b>>=1)
if(b&1)ans=ans*a%t;
return ans;
}
int main(){
LL i,j,n,t=0,odd=0,ans;
scanf("%s",s+1);
n=strlen(s+1);
for(i=1;i<=n;i++)
cnt[s[i]-'a'+1]++;
for(i=1;i<=26;i++){
if(cnt[i]&1)odd++;
cnt[i]>>=1;
}
t=n>>1;
if(odd>1){
cout<<"0";return 0;
}
f[0]=1;
for(i=1;i<=t;i++)f[i]=f[i-1]*i%mod;
for(i=1;i<=t;i++)
r[i]=power_mod(f[i],mod-2,mod);
ans=f[t];
for(i=1;i<=26;i++)
if(cnt[i])ans=ans*r[cnt[i]]%mod;
cout<<ans%mod<<endl;
return 0;
}