BZOJ3160 万径人踪灭(FFT+manacher)

时间:2021-12-05 12:12:44

  容易想到先统计回文串数量,这样就去掉了不连续的限制,变为统计回文序列数量。

  显然以某个位置为对称轴的回文序列数量就是2其两边(包括自身)对称相等的位置数量-1。对称有啥性质?位置和相等。这不就是卷积嘛。那么就做完了。

  又写挂manacher,没救。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 270000
#define P 1000000007
int n,m,s[N],t,r[N],f[N],p[N],ans=;
const double PI=3.14159265358979324;
struct complex
{
double x,y;
complex operator +(const complex&a) const
{
return (complex){x+a.x,y+a.y};
}
complex operator -(const complex&a) const
{
return (complex){x-a.x,y-a.y};
}
complex operator *(const complex&a) const
{
return (complex){x*a.x-y*a.y,x*a.y+y*a.x};
}
}a[N],b[N];
void DFT(int n,complex *a,int p)
{
for (int i=;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int i=;i<=n;i<<=)
{
complex wn=(complex){cos(*PI/i),p*sin(*PI/i)};
for (int j=;j<n;j+=i)
{
complex w=(complex){,};
for (int k=j;k<j+(i>>);k++,w=w*wn)
{
complex x=a[k],y=w*a[k+(i>>)];
a[k]=x+y,a[k+(i>>)]=x-y;
}
}
}
}
void mul(int n,complex *a,complex *b)
{
for (int i=;i<n;i++) a[i].y=a[i].x-b[i].x,a[i].x=a[i].x+b[i].x;
DFT(n,a,);
for (int i=;i<n;i++) a[i]=a[i]*a[i];
DFT(n,a,-);
for (int i=;i<n;i++) a[i].x=a[i].x/n/;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3160.in","r",stdin);
freopen("bzoj3160.out","w",stdout);
const char LL[]="%I64d";
#else
const char LL[]="%lld";
#endif
char c=getchar();
while (c=='a'||c=='b') s[n++]=c-,c=getchar();
m=n*-;
t=;while (t<m) t<<=;
for (int i=;i<t;i++) r[i]=(r[i>>]>>)|(i&)*(t>>);
for (int i=;i<n;i++) a[i].x=b[i].x=s[i]-;
mul(t,a,b);
for (int i=;i<m;i++) f[i]=(int){a[i].x+0.5};
for (int i=;i<t;i++) a[i].x=a[i].y=b[i].x=b[i].y=;
for (int i=;i<n;i++) a[i].x=b[i].x=-s[i];
mul(t,a,b);
for (int i=;i<m;i++) f[i]+=(int){a[i].x+0.5};
for (int i=;i<m;i++) f[i]=f[i]+>>;
p[]=;
for (int i=;i<m;i++) p[i]=(p[i-]<<)%P;
for (int i=;i<m;i++) ans=(ans+p[f[i]]-)%P;
for (int i=m-;~i;i--) s[i]=(i&?:s[i>>]);
for (int i=m;i;i--) s[i]=s[i-];
s[]=s[++m]=;
memset(r,,sizeof(r));
r[]=;int x=;
for (int i=;i<=m;i++)
{
if (x+r[x]>=i) r[i]=min(r[x-(i-x)],x+r[x]-i);
while (i-r[i]->=&&i+r[i]+<=m&&s[i+r[i]+]==s[i-r[i]-]) r[i]++;
if (i+r[i]>=x+r[x]) x=i;
}
for (int i=;i<=m;i++) ans=(ans-(r[i]+>>)+P)%P;
cout<<ans;
return ;
}