bzoj3160 萬徑人蹤滅(manacher+FFT)

bzoj3160 萬徑人蹤滅

原題地址http://www.lydsy.com/JudgeOnline/problem.php?id=3622

題意:
給定一個長度爲N且只有a,b的字符串,問有多少種方案從中選取一個子序列,使得:
1.位置和字符都關於某條對稱軸對稱。
2.不能是連續的一段。
這裏寫圖片描述
這裏寫圖片描述

數據範圍
n<=100000

題解:
首先求不連續的,就先求所有的,再用manacher求連續的剪掉即可。
關鍵大概就是想到以每個位置爲中心,兩邊對稱相同的有多少對fi ,這個中心的答案就是2fi1

fi=j=0i[sij==si+j]
當然有夾縫處,於是我們把i數組下標擴大一倍:
fi=[j+k==i] [sj==sk] ,這是一個卷積的形式。
介於0x0=0,1x0=0,1x1=1,
我們想到了規定某一種字符係數爲1,然後fft做多項式乘法,這樣只有相同的纔會貢獻。

對a做一遍FFT,對b做一遍FFT,加一起再IDFT,得到f 數組,減去manacher的答案即可。

代碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
const int mod=1000000007;
const int MXN=530000;
const double Pi=acos(-1);
struct Virt
{
    double r,i;
    Virt(){}
    Virt(double r,double i):r(r),i(i){}
    Virt operator+(const Virt &A){return Virt(r+A.r,i+A.i);}
    Virt operator-(const Virt &A){return Virt(r-A.r,i-A.i);}
    Virt operator*(const Virt &A){return Virt(r*A.r-i*A.i,r*A.i+i*A.r);}
}omg[MXN],_omg[MXN],a[MXN],b[MXN],c[MXN];
int len,n,p,R[MXN],po[MXN],v[MXN];
char s[MXN];
void FFT(Virt *x,int opt)
{
    Virt *w; if(opt==1) w=omg; else w=_omg;
    for(int i=0;i<n;i++) if(i<R[i]) swap(x[i],x[R[i]]);
    for(int m=2;m<=n;m=m<<1) 
    {
        int l=m>>1;
        for(int j=0;j<n;j+=m)
        {
            for(int i=0;i<l;i++)
            {
                Virt y=x[j+i+l]*w[n/m*i];
                x[j+i+l]=x[j+i]-y;
                x[j+i]=x[j+i]+y;
            }
        }
    }
    if(opt==-1) for(int i=0;i<n;i++) x[i].r=x[i].r/(double)n;
}
int manacher()
{
    for(int i=len;i>=0;i--) s[2*i+1]='#',s[2*i+2]=s[i]; s[0]='+'; s[2*len+2]='-';
    int mx=0,id=0; int ret=0;
    for(int i=1;i<=2*len;i++)
    {
        if(id+mx>i) v[i]=min(v[2*id-i],id+mx-i);
        else v[i]=1;
        while(s[i+v[i]]==s[i-v[i]]) v[i]++;
        if(i+v[i]>id+mx) id=i,mx=v[i];
        ret=(ret+v[i]/2)%mod;
    }
    return ret;
}
int main()
{
    scanf("%s",s); len=strlen(s);

    int m; for(p=0,n=1,m=2*len;n<m;n=n<<1,p++);
    po[0]=1; for(int i=1;i<=n;i++) po[i]=(po[i-1]*2)%mod;
    R[0]=0; for(int i=1;i<n;i++) {R[i]=(R[i>>1]>>1)|((i&1)<<(p-1));}
    for(int i=0;i<n;i++){omg[i]=Virt(cos(2.0*Pi/(double)n*i),sin(2.0*Pi/(double)n*i)); _omg[i]=Virt(omg[i].r,-omg[i].i);}
    for(int i=0;i<n;i++) {a[i]=Virt((s[i]=='a'),0); b[i]=Virt((s[i]=='b'),0);}
    FFT(a,1);   FFT(b,1);       
    for(int i=0;i<n;i++) c[i]=a[i]*a[i]+b[i]*b[i];
    FFT(c,-1);
    int ret=0; for(int i=0;i<n;i++) {ret=(ret+po[((int)(c[i].r+0.5)+1)/2])%mod; ret--; if(ret<0) ret+=mod;}
    ret=(ret-manacher()+mod)%mod;
    printf("%d\n",ret);
    return 0;
}
發佈了203 篇原創文章 · 獲贊 43 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章