[BZOJ4259]残缺的字符串

题目大意

给定模板串 A 和母串 B ,长度分别为 m n ,你需要统计模板串在母串中所有出现的位置。
字符集都是小写拉丁字母,而且存在通配符 能够匹配任意字符。

1m,n3×105

题目分析

考虑将 A 串倒置,然后令

ai=0,ord(Ai)ord(a)+1,Ai is otherwise

B 串同理,那么我们令
Fi=j=0i(aibi)2aibi

如果 i 为结尾能够匹配模板串,就有 Fi=0 ,将上式拆开可以变成一个卷积形式,使用FFT就好了。
时间复杂度 O(nlogn)

代码实现

为什么我的DFT跑起来的时间是别人的两倍。。。
于是BZOJ上T成狗。。。
有没有大神来指明一下哪里常数大了???

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>

#define sqr(x) (x*x)
#define cube(x) (x*x*x)

using namespace std;

typedef double db;

int buf[30];

void write(int x)
{
    if (x<0) putchar('-'),x=-x;
    for (;x;x/=10) buf[++buf[0]]=x%10;
    if (!buf[0]) buf[++buf[0]]=0;
    for (;buf[0];putchar('0'+buf[buf[0]--]));
}

const db pi=acos(-1);
const int N=524300;

struct Z
{
    db x,y;

    inline Z(){}  
    inline Z(db x_,db y_):x(x_),y(y_){};  
    inline Z operator+(Z const p){return Z(x+p.x,y+p.y);}
    inline Z operator-(Z const p){return Z(x-p.x,y-p.y);}
    inline Z operator*(Z const p){return Z(x*p.x-y*p.y,x*p.y+y*p.x);}
    inline Z operator/(db const k){return Z(x/k,y/k);}
}A[N],B[N],C[N],t[N],omega[N];

db S_[N],T_[N],res[N];
int trs[N],mat[N];
char S[N],T[N];
int n,m,L,cnt;

void DFT(Z *a,int len,int sig)
{
    for (int i=0;i<len;++i) t[trs[i]]=a[i];
    Z w;
    for (int l=2,half,p;l<=len;l<<=1)
    {
        half=l>>1,p=len/l;
        for (int i=0;i<half;++i)
        {
            w=omega[sig>0?p*i:len-p*i];
            for (int j=i;j<len;j+=l)
            {
                Z u=t[j],v=w*t[j+half];
                t[j]=u+v,t[j+half]=u-v;
            }
        }
    }
    for (int i=0;i<len;++i) a[i]=t[i];
}

void pre()
{
    for (L=1;L<n||L<m;L<<=1);
    for (int i=0;i<L;++i)
    {
        int ret=0;
        for (int j=1,x=i;j<L;j<<=1,x>>=1) ret=ret<<1|(x&1);
        trs[i]=ret;
    }
    for (int i=0;i<=L;++i) omega[i]=Z(cos(2.*pi*i/L),sin(2.*pi*i/L));
}

void calc()
{
    for (int i=0;i<n;++i) S_[i]=S[i]=='*'?0:S[i]-'a'+1;
    for (int i=0;i<m;++i) T_[i]=T[i]=='*'?0:T[i]-'a'+1;
    for (int i=0;i<L;++i) A[i]=Z(cube(S_[i]),0);
    for (int i=0;i<L;++i) B[i]=Z(T_[i],0);
    DFT(A,L,1),DFT(B,L,1);
    for (int i=0;i<L;++i) C[i]=A[i]*B[i];
    DFT(C,L,-1);
    for (int i=0;i<n;++i) C[i]=C[i]/L;
    for (int i=0;i<n;++i) res[i]=round(C[i].x);
    for (int i=0;i<L;++i) A[i]=Z(sqr(S_[i]),0);
    for (int i=0;i<L;++i) B[i]=Z(sqr(T_[i]),0);
    DFT(A,L,1),DFT(B,L,1);
    for (int i=0;i<L;++i) C[i]=A[i]*B[i];
    DFT(C,L,-1);
    for (int i=0;i<n;++i) C[i]=C[i]/L;
    for (int i=0;i<n;++i) res[i]-=2.*round(C[i].x);
    for (int i=0;i<L;++i) A[i]=Z(S_[i],0);
    for (int i=0;i<L;++i) B[i]=Z(cube(T_[i]),0);
    DFT(A,L,1),DFT(B,L,1);
    for (int i=0;i<L;++i) C[i]=A[i]*B[i];
    DFT(C,L,-1);
    for (int i=0;i<n;++i) C[i]=C[i]/L;
    for (int i=0;i<n;++i) res[i]+=round(C[i].x);
}

int main()
{
    freopen("string.in","r",stdin),freopen("string.out","w",stdout);
    scanf("%d%d",&m,&n);
    scanf("%s",T),scanf("%s",S),reverse(T,T+m),pre();
    calc();
    for (int i=m-1;i<n;++i)
        if (fabs(res[i])<=1e-8) mat[++cnt]=i+2-m;
    write(cnt),putchar('\n');
    for (int i=1;i<=cnt;++i) write(mat[i]),putchar(i<cnt?' ':'\n');
    fclose(stdin),fclose(stdout);
    return 0;
}

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