FFT+manacher--bzoj3160: 萬徑人蹤滅
阿新 • • 發佈:2018-11-26
一道隱蔽的
題目要求迴文子序列的個數,不能連續的話就用全部的減去連續的,連續的可以用
計算,全部的迴文子序列怎麼求呢?
因為這個序列中只有
和
,假設
,那麼兩個位置的字元都是
就是相乘為
(
的反著來同理)。
這樣的話以
為中心的迴文子序列就可以看成
這樣的形式,兩邊的下標相加為定值,就可以使用
來實現。
也就是傳說中的“我卷我自己”。
算答案的時候 位置的值就是 位置為中心的對稱相等的個數,假設為 ,那麼這個位置答案就是 ,所有位置相加再減去 求出的迴文子串個數就是最後的答案
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 400005
#define int long long
using namespace std;
const int mod=1e9+7;
const double Pi=acos(-1.0);
struct complex{
double x,y;
complex(double xx=0,double yy=0){x=xx,y=yy;}
}a[maxn],b[maxn];
complex operator +(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
complex operator -(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
complex operator *(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
int n,limit=1,l,rev[maxn],bin[maxn],len[maxn],ans;
char s[maxn],tmp[maxn];
void FFT(complex *F,int type){
for(int i=0;i<limit;i++)
if(i<rev[i]) swap(F[i],F[rev[i]]);
for(int mid=1;mid<limit;mid<<=1){
complex Wn(cos(Pi/mid),1.0*type*sin(Pi/mid));
for(int r=mid<<1,j=0;j<limit;j+=r){
complex w(1,0);
for(int k=0;k<mid;k++,w=w*Wn){
complex x=F[j+k],y=w*F[j+mid+k];
F[j+k]=x+y,F[j+mid+k]=x-y;
}
}
}
}
inline void prework(){
for(int i=0;i<n;i++)
if(s[i]=='a') a[i].x=1,b[i].x=0;
else b[i].x=1,a[i].x=0;
while(limit<2*n) limit<<=1,l++;
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
bin[0]=1;
for(int i=1;i<=n;i++) bin[i]=(bin[i-1]<<1)%mod;
}
inline int init(char *p){
tmp[0]='@';
for(int i=1;i<=2*n;i+=2)
tmp[i]='#',tmp[i+1]=p[i/2];
tmp[2*n+1]='#'; tmp[2*n+2]='$';
return 2*n+1;
}
inline int manacher(char *p,int m){
int mx=0,pos=0,tot=0;
for(int i=1;i<=m;i++){
if(mx>i) len[i]=min(mx-i,len[2*pos-i]);
else len[i]=1;
while(p[i-len[i]]==p[i+len[i]]) len[i]++;
if(len[i]+i>mx) mx=len[i]+i,pos=i;
tot+=(len[i]/2)%mod;
} return tot;
}
signed main(){
scanf("%s",s); n=strlen(s);
prework();
FFT(a,1); FFT(b,1);
for(int i=0;i<=limit;i++) a[i]=a[i]*a[i],a[i]=a[i]+b[i]*b[i];
FFT(a,-1);
for(int i=0;i<=2*n-2;i++){
int xx=(int)((a[i].x+0.5)/limit);
xx=(xx+1)>>1;
(ans+=bin[xx]-1)%=mod;
}
int m=init(s); ans-=manacher(tmp,m)%mod;
printf("%d\n",(ans+mod)%mod);
return 0;
}