BZOJ 4503 兩個串 FFT

Solution

題目要求:
給定兩個串,問第二個串在第一個串的哪些位置出現過
第二個串中有通配符’?’

乍一眼看上去是一個KMP?
但是因爲通配符的存在使得nxt 數組直接報廢

當然,DP 也是可以的
但是自己感受那令人絕望的時間複雜度吧

考慮將其轉化爲數字串做減法
設第一個串爲a ,第二個串爲b ,長度分別爲la,lb
在沒有通配符的情況下
若兩串在某個位置匹配,則一定有

i=xx+lb1(a[i]b[i])2=0

拆開
i=xx+lb1a[i]2+b[i]22a[i]b[i]=0

發現很好化爲卷積和的形式,只需要將b 反序即可
i=xlb+1xa[i]2+b[xi]22a[i]b[xi]=0

PS:這裏的x 換了一下,這是爲了卷積方便

所以將a ,b 卷積一下即可

現在考慮加入通配符?
我們要求不管是a[i]=b[i] 還是b[i]=? 其結果都是0
那麼將整體都乘上一個b[i] 即可

原式變爲

i=xlb+1xa[i]2b[xi]+b[xi]32a[i]b[xi]2=0

並且分析發現,b[xi]3 是不需要卷積的
因爲若匹配,則b 的每一位都需要貢獻一個b[i]3 ,所以直接預處理出來

代碼如下:

#include <bits/stdc++.h>
using namespace std;
const int N =100010;
const double pi=acos(-1);
char str[N];
struct Complex {
    double x;
    double y;
    Complex() {};
    Complex(double _x,double _y) { x=_x;y=_y; }
    Complex operator + (const Complex o) { return Complex(x+o.x,y+o.y); }
    Complex operator - (const Complex o) { return Complex(x-o.x,y-o.y); }
    Complex operator * (const Complex o) { return Complex(x*o.x-y*o.y,x*o.y+y*o.x); }
}a[N<<2],_a[N<<2],b[N<<2],_b[N<<2];
int r[N<<2];
int n,m,L,R,sum;
void fft(Complex *now,int f,int n) {
    for(int i=0;i<n;++i)
        if(i<r[i]) swap(now[i],now[r[i]]);
    for(int i=1;i<n;i<<=1) {
        Complex wn(cos(pi/i),f*sin(pi/i));//w_n^i;
        for(int j=0;j<n;j+=(i<<1)) {
            Complex w(1,0);
            for(int k=0;k<i;++k,w=w*wn) {
                Complex x=now[j+k],y=w*now[j+k+i];
                now[j+k]=x+y;
                now[j+k+i]=x-y;
            }
        }
    }
    if(f==-1)
        for(int i=0;i<n;++i)
            now[i].x/=n;
}
int main() {
    scanf("%s",str);
    R=n=strlen(str);
    for(int i=0;i<n;++i) {
        a[i].x=str[i]-'a'+1;
        _a[i].x=a[i].x*a[i].x;//a^2
    }
    scanf("%s",str);
    L=m=strlen(str);
    for(int i=0;i<m;++i) {
        if(str[i]!='?') b[m-i-1].x=str[i]-'a'+1;
        sum+=b[m-i-1].x*b[m-i-1].x*b[m-i-1].x;//b^3
        _b[m-i-1].x=b[m-i-1].x*b[m-i-1].x;//b^2
    }
    m+=n;
    int nn=0;
    for(n=1;n<=m;n<<=1) nn++;
    for(int i=0;i<n;++i) { r[i]=(r[i>>1]>>1)|((i&1)<<(nn-1)); }

    fft(_a,1,n);fft(b,1,n);
    for(int i=0;i<=n;++i) { b[i]=_a[i]*b[i]; }
    fft(b,-1,n);
    //*******a^2*b
    fft(a,1,n);fft(_b,1,n);
    for(int i=0;i<=n;++i) { a[i]=a[i]*_b[i]; }
    fft(a,-1,n);
    //*******a*b^2
    for(int i=0;i<=n;++i) {
        a[i].x=(int)(a[i].x+0.5);
        b[i].x=(int)(b[i].x+0.5);
    }
    int times=0;
    for(int i=L-1;i<=R-1;++i)
        if(b[i].x+sum-2*a[i].x==0)
            ++times;
    printf("%d\n",times);
    for(int i=L-1;i<=R-1;++i)
        if(b[i].x+sum-2*a[i].x==0)
            printf("%d\n",i-L+1);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章