bzoj3160: 万径人踪灭

题面传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3160


思路:首先题目中不要连续的回文串,那么答案就是总的回文串-连续回文串

连续回文串用manacher就可以O(n)搞出来

现在的问题是求总的回文串。

既然是回文串,我们就想到枚举对称轴

为了方便表示在字符的夹缝的对称轴,下标*2,下标为奇数则为夹缝。

令f[i]为对称轴为i时两边相同的字符对数,那么答案就是sigma (2^f[i])-1

现在的问题是快速求f[i]

令a[i]表示原串第i个为是否为a,b[i]表示原串第i个为是否为b;

那么f[i]=sigma a[j]*a[k]+sigma b[x]+b[y] (j+k=i,x+y=i,j<=k,x<=y)

这不就是卷积

上FFT搞一搞就可以了

被递归版代码常数吓傻,卡着时限A...

#include<ctime>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=270010,mod=1000000007;
const double pi=M_PI;
using namespace std;
struct plex{
    double r,i;
}tmp[maxn];
 
plex operator +(plex a,plex b){return (plex){a.r+b.r,a.i+b.i};}
plex operator -(plex a,plex b){return (plex){a.r-b.r,a.i-b.i};}
plex operator *(plex a,plex b){return (plex){a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r};}
 
struct DFT{
    plex a[maxn];
    void fft(int bg,int step,int size,int op){
        if (size==1) return;
        fft(bg,step<<1,size>>1,op),fft(bg+step,step<<1,size>>1,op);
        plex w=(plex){1,0},t=(plex){cos(2*pi/size),sin(2*pi*op/size)};
        int p=bg,p0=bg,p1=bg+step;
        for (int i=0;i<size/2;i++){
            tmp[p]=a[p0]+w*a[p1];
            tmp[p+size/2*step]=a[p0]-w*a[p1];
            p+=step,p0+=step*2,p1+=step*2,w=w*t;
        }
        for (int i=bg;size;size--,i+=step) a[i]=tmp[i];
    }
}a,b;
int f[maxn<<1],len,n,nn,POW[maxn],ans;char str[maxn],s[maxn<<1];
 
int manacher(){
    int i,res=0;
    for (s[0]='$',s[1]='#',i=1;i<=n;i++) s[i<<1]=str[i-1],s[(i<<1)|1]='#';
    n=(n<<1)|1;
    int mx=1,id=1;
    for (int i=1;i<=n;i++){
        f[i]=min(f[id+id-i],mx-i);
        for (;s[i+f[i]]==s[i-f[i]];) f[i]++;
        if (f[i]+i>mx) mx=f[i]+i,id=i;
        res+=f[i]>>1,res%=mod;
    }
    return res;
}
 
int main(){
    POW[0]=1;for (int i=1;i<maxn;i++) POW[i]=(POW[i-1]<<1)%mod;
    scanf("%s",str),n=strlen(str);
    for (nn=1;nn<(n<<1);nn<<=1);
    for (int i=0;i<n;i++) a.a[i].r=(str[i]=='a'?1.0:0.0);
    for (int i=0;i<n;i++) b.a[i].r=(str[i]=='b'?1.0:0.0);
    a.fft(0,1,nn,1),b.fft(0,1,nn,1);
    for (int i=0;i<nn;i++)
    	a.a[i]=a.a[i]*a.a[i]+b.a[i]*b.a[i];
    a.fft(0,1,nn,-1);
    for (int i=0;i<nn;i++) a.a[i].r/=nn;
    for (int i=0;i<nn;i++){
        int x=(int)(round(a.a[i].r)+1)>>1;
        ans=(ans+POW[x]-1)%mod;
    }
    //int t=(int)clock();
    printf("%d\n",(ans-manacher()+mod)%mod);//
    //printf("%d\n",(int)clock()-t);
    return 0;
}




你可能感兴趣的:(fft,Manacher)