【BZOJ3160】【2013湖北互测week1】—万径人踪灭(FFT+Manacher)
题意:给定一个串,问有多少个满足位置对称的不连续回文子序列
考虑计算出出所有位置对称的回文子序列和所有连续回文子串
后者可以直接用求出
考虑前一部分怎么求
对于每个对称轴的位置单独考虑
发现和没有关系,只需要看和相等的个数就可以了
即
考虑对于分别求出相等的个数再求和
比如,令所有为的位置为,否则为
那是
一下就可以了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=100005;
const int mod=1e9+7;
const double pi=acos(-1);
struct plx{
double x,y;
plx(double _x=0,double _y=0):x(_x),y(_y){}
friend inline plx operator +(const plx &a,const plx &b){
return plx(a.x+b.x,a.y+b.y);
}
friend inline plx operator -(const plx &a,const plx &b){
return plx(a.x-b.x,a.y-b.y);
}
friend inline plx operator *(const plx &a,const plx &b){
return plx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}
}a[N<<2],b[N<<2];
int rev[N<<2],lim=1,tim;
inline void fft(plx *f,int kd){
for(re int i=0;i<lim;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
for(re int mid=1;mid<lim;mid<<=1){
plx now=plx(cos(pi/mid),kd*sin(pi/mid));
for(re int i=0;i<lim;i+=(mid<<1)){
plx w=plx(1,0);
for(re int j=0;j<mid;j++,w=w*now){
plx a0=f[i+j],a1=w*f[i+j+mid];
f[i+j]=a0+a1,f[i+j+mid]=a0-a1;
}
}
}
if(kd==-1)for(re int i=0;i<lim;i++)f[i].x/=lim;
}
char now[N<<2],s[N];
int n;
ll pw[N],ans;
int mx,mid,p[N<<2];
inline void add(ll &a,int b){
a=(a+b>=mod)?a+b-mod:a+b;
}
inline ll manacher(){
int len=strlen(s);ll res=0;
now[0]='!',now[1]='$',n=1;
for(re int i=0;i<len;i++){
now[++n]=s[i],now[++n]='$';
}
now[n+1]='@';
mx=mid=1;
for(re int i=1;i<=n;i++){
if(i<mx)p[i]=min(mx-i,p[2*mid-i]);
else p[i]=1;
while(now[i-p[i]]==now[i+p[i]])p[i]++;
if(mx<i+p[i])mx=i+p[i],mid=i;
add(res,(p[i])/2);
}return res;
}
int main(){
scanf("%s",s);
int len=strlen(s);
for(re int i=0;i<len;i++){
if(s[i]=='a')a[i].x=1;
else b[i].x=1;
}
while(lim<=len*2)lim<<=1,tim++;
for(re int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(tim-1));
fft(a,1);
fft(b,1);for(re int i=0;i<lim;i++) a[i]=a[i]*a[i],a[i]=a[i]+b[i]*b[i];
fft(a,-1);
pw[0]=1;for(re int i=1;i<=len;i++)pw[i]=pw[i-1]*2%mod;
for(re int i=0;i<=2*len+2;i++){
int k=(a[i].x+0.5);
k=(k+1)/2;add(ans,pw[k]-1);
}
cout<<(ans-manacher()+mod)%mod<<'\n';
}