【BZOJ3160】万径人踪灭
题面
题目分析
我们来看一看一个回文串满足什么:
对于回文串,如果中点一定,所有以它为中点的点对下标之和也一定。
我们设下标为\(i\),点对个数之和为\(f(i)\),则方案数为\(2^{f(i)}-1\)。
显然有\(f(x)=((\sum\limits_{i=1}^{x-1}[s[i]=s[x-i]])+1)/2\)。
其中\(\sum\limits_{i=1}^{x-1}[s[i]=s[x-i]]\)可以视作一个卷积的形式;
我们指定字符,如a,则把\(s[i]=\)a的位置赋初值为\(1\),然后进行卷积即可。
因此,\(f(x)\)的答案为指定字符分别为a,b的卷积结果之和\(+1/2\)。
代码实现
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<complex>
#define MAXN 0x7fffffff
typedef long long LL;
const int N=400005,mod=1e9+7;
using namespace std;
inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
typedef complex<double> Z;
const double Pi=M_PI;
void FFT(Z *a,int x,int K){
static int rev[N],lst;
int n=1<<x;
if(n!=lst){
for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
lst=n;
}
for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int i=1;i<n;i<<=1){
int tmp=i<<1;
Z wn(cos(Pi/i),sin(Pi*K/i));
for(int j=0;j<n;j+=tmp){
Z w(1,0);
for(int k=0;k<i;k++,w=w*wn){
Z x=a[j+k],y=a[i+j+k]*w;
a[j+k]=x+y,a[i+j+k]=x-y;
}
}
}
if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
}
Z a[N],b[N],c[N];
string sr;
int ksm(int x,int k){
int ret=1;
while(k){
if(k&1)ret=(LL)ret*x%mod;
x=(LL)x*x%mod,k>>=1;
}
return ret;
}
int ans;
char now[N];int p[N];
void Manacher(string s){
int len=s.length();
for(int i=1;i<=len;i++)now[2*i-1]='%',now[2*i]=s[i-1];
now[len=len*2+1]='%';
int pos=0,R=0;
for (int i=1;i<=len;i++){
if(i<R)p[i]=min(p[2*pos-i],R-i); else p[i]=1;
while(1<=i-p[i]&&i+p[i]<=len&&now[i-p[i]]==now[i+p[i]]) p[i]++;
if(i+p[i]>R)R=i+p[i],pos=i;
ans=(ans-p[i]/2+mod)%mod;
}
}
int main(){
cin>>sr;
int len=sr.length();
int x=ceil(log2(len<<1|1));
for(int i=0;i<len;i++)a[i].real()=(sr[i]=='a'),b[i].real()=(sr[i]=='a');
FFT(a,x,1),FFT(b,x,1);
for(int i=0;i<(1<<x);i++)c[i]=a[i]*b[i];
fill(a,a+(1<<x),0),fill(b,b+(1<<x),0);
for(int i=0;i<len;i++)a[i].real()=(sr[i]=='b'),b[i].real()=(sr[i]=='b');
FFT(a,x,1),FFT(b,x,1);
for(int i=0;i<(1<<x);i++)c[i]+=a[i]*b[i];
FFT(c,x,-1);
for(int i=0;i<(1<<x);i+=2)c[i].real()++;
for(int i=0;i<(len<<1)-1;i++)ans=(ans+ksm(2,((int)(c[i].real()+0.5))/2)-1)%mod;
Manacher(sr);
cout<<ans;
return 0;
}