【BZOJ3160】【2013湖北互测week1】—万径人踪灭(FFT+Manacher)

传送门

题意:给定一个串,问有多少个满足位置对称的不连续回文子序列

考虑计算出出所有位置对称的回文子序列和所有连续回文子串
后者可以直接用ManacherManacher求出

考虑前一部分怎么求

对于每个对称轴的位置ii单独考虑
发现和a,ba,b没有关系,只需要看s[ik]s[i-k]s[i+k]s[i+k]相等的个数就可以了
k[s[i+k]==s[ik]]\sum_{k}[s[i+k]==s[i-k]]
考虑对于a,ba,b分别求出相等的个数再求和
比如aa,令所有为aa的位置为11,否则为00
那是ks[ik]s[i+k]\sum_{k}s[i-k]*s[i+k]
fftfft一下就可以了

#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';
}
posted @ 2019-03-25 16:19  Stargazer_cykoi  阅读(83)  评论(0编辑  收藏  举报