[bzoj4503]两个串

来源:互联网 发布:储罐设计软件 编辑:程序博客网 时间:2024/06/05 17:06

题目大意

兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。

FFT

我们把T串反过来。
设a表示S串(把字符转成不为0的数字)
b表示T串,其中问号可以用一个0表示
c[j+m1]=(a[j+i]b[mi1])2a[j+i]b[mi1]
容易证明S串的第j个位置为开头能匹配T串则c[j+m-1]=0。
而右边的含义就是T的第i能否匹配S的第j+i。
由于贡献一定非负,最终为0一定是每一项均为0,也就是匹配成功。
后面的拆一下可以做三次FFT完成。

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef double db;const db pi=acos(-1);const int maxn=530000+10;struct node{    db x,y;    friend node operator +(node a,node b){        node c;        c.x=a.x+b.x;c.y=a.y+b.y;        return c;    }    friend node operator -(node a,node b){        node c;        c.x=a.x-b.x;c.y=a.y-b.y;        return c;    }    friend node operator *(node a,node b){        node c;        c.x=a.x*b.x-a.y*b.y;c.y=a.x*b.y+a.y*b.x;        return c;    }};node a[maxn],b[maxn],c[maxn],d[maxn],e[maxn],f[maxn],tt[maxn],w[maxn];int rev[maxn],ans[maxn];db ce;char s[maxn],h[maxn];int i,j,k,l,t,n,m,mx,len,top;int pow(int x,int y){    if (y==2) return x*x;    else return x*x*x;}void prepare(){    w[0].x=1;w[0].y=0;    w[1].x=cos(2*pi/len);w[1].y=sin(2*pi/len);    fo(i,2,len) w[i]=w[i-1]*w[1];    fo(i,0,len-1){        int p=0;        for (int j=0,tp=i;j<ce;j++,tp/=2) p=(p<<1)+(tp%2);        rev[i]=p;    }}void DFT(node *a,int sig){    int i;    fo(i,0,len-1) tt[rev[i]]=a[i];    for (int m=2;m<=len;m*=2){        int half=m/2,bei=len/m;        fo(i,0,half-1){            node wi=sig>0?w[i*bei]:w[len-i*bei];            for (int j=i;j<len;j+=m){                node u=tt[j],v=tt[j+half]*wi;                tt[j]=u+v;                tt[j+half]=u-v;            }        }    }    if (sig==-1)        fo(i,0,len-1) tt[i].x/=len;    fo(i,0,len-1) a[i]=tt[i];}void FFT(node *a,node *b,node *c){    int i;    fo(i,0,len-1) e[i]=a[i],f[i]=b[i];    DFT(e,1);DFT(f,1);    fo(i,0,len-1) e[i]=e[i]*f[i];    DFT(e,-1);    fo(i,0,len-1) c[i]=e[i];}int main(){    //freopen("4503.in","r",stdin);    scanf("%s",s);    n=strlen(s);    scanf("%s",h);    m=strlen(h);    mx=max(n,m);    len=1;    while (len<mx*2) len*=2;    ce=log(len)/log(2);    prepare();    reverse(h,h+m);    fo(i,0,n-1)        a[i].x=pow(s[i]-'a'+1,3);    fo(i,0,m-1)        b[i].x=(h[i]=='?'?0:h[i]-'a'+1);    FFT(a,b,d);    fo(i,0,len-1) c[i]=c[i]+d[i];    fo(i,0,n-1)        a[i].x=-2*pow(s[i]-'a'+1,2);    fo(i,0,m-1)        b[i].x=pow(h[i]=='?'?0:h[i]-'a'+1,2);    FFT(a,b,d);    fo(i,0,len-1) c[i]=c[i]+d[i];    fo(i,0,n-1)        a[i].x=s[i]-'a'+1;    fo(i,0,m-1)        b[i].x=pow(h[i]=='?'?0:h[i]-'a'+1,3);    FFT(a,b,d);    fo(i,0,len-1) c[i]=c[i]+d[i];    fo(i,0,n-m)         if (int(c[i+m-1].x)==0) ans[++top]=i;    printf("%d\n",top);    fo(i,1,top) printf("%d\n",ans[i]);}
0 0
原创粉丝点击