bzoj4403 两个串

Description

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

Input

两行两个字符串,分别代表S和T

Output

第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。

两个串a,b相等(b中有通配符)当且仅当Σ(a[i]-b[i])2b[i]=0,其中a[i],b[i]为对应字符的对应编号,且通配符对应0

翻转S串并把T串用0补至与S等长后上式可化为卷积形式用fft计算

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
int N,P;
const double pi=3.14159265358979323846;
int r[524288];
struct cplx{
    double a,b;
    inline cplx(double r=0,double i=0){a=r;b=i;}
    inline cplx operator+(cplx x){return cplx(a+x.a,b+x.b);}
    inline cplx operator-(cplx x){return cplx(a-x.a,b-x.b);}
    inline cplx operator*(cplx x){return cplx(a*x.a-b*x.b,a*x.b+b*x.a);}
}a[524288],b[524288];
void dft(cplx*a,int t){
    for(int i=0;i<N;i++)if(i>r[i])std::swap(a[i],a[r[i]]);
    for(int i=1;i<N;i<<=1){
        cplx w(cos(pi/i),t*sin(pi/i));
        for(int j=0;j<N;j+=i<<1){
            cplx e(1),*b=a+j,*c=b+i;
            for(int k=0;k<i;k++,e=e*w){
                cplx x=b[k],y=c[k]*e;
                b[k]=x+y,c[k]=x-y;
            }
        }
    }
}
char s1[200005],s2[200005];
int v1[200005],v2[200005];
int h1[200005],h2[200005];
int as[200005],ap=0;
int l1,l2,h3=0;
int main(){
    input:{
        scanf("%s%s",s1,s2);
        l1=strlen(s1)-1;
        l2=strlen(s2)-1;
        for(int i=0;i<=l1;i++)v1[i]=s1[l1-i]-'a'+1;
        for(int i=0;i<=l2;i++)v2[i]=s2[i]!='?'?s2[i]-'a'+1:0;
        for(int i=0;i<=l2;i++)h3+=v2[i]*v2[i]*v2[i];
    }
    init:{
        for(N=2,P=0;N<=l1+1;N<<=1,++P);
        N<<=1,++P;
        for(int i=1;i<N;i++)r[i]=r[i>>1]>>1|(i&1)<<P;
    }
    calc:{
        for(int i=0;i<=l1;i++)a[i]=cplx(v1[i]*v1[i]);
        for(int i=0;i<=l1;i++)b[i]=cplx(v2[i]);
        for(int i=l1+1;i<N;i++)a[i]=b[i]=cplx();
        dft(a,1),dft(b,1);
        for(int i=0;i<N;i++)a[i]=a[i]*b[i];
        dft(a,-1);
        for(int i=0;i<=l1;i++)h1[i]=(int)(a[i].a/N+0.5);
        
        for(int i=0;i<=l1;i++)a[i]=cplx(v1[i]);
        for(int i=0;i<=l1;i++)b[i]=cplx(v2[i]*v2[i]);
        for(int i=l1+1;i<N;i++)a[i]=b[i]=cplx(0,0);
        dft(a,1),dft(b,1);
        for(int i=0;i<N;i++)a[i]=a[i]*b[i];
        dft(a,-1);
        for(int i=0;i<=l1;i++)h2[i]=(int)(a[i].a/N+0.5);
    }
    output:{
        for(int i=l1;i>=l2;i--)if(h1[i]-2*h2[i]+h3==0)as[ap++]=l1-i;
        printf("%d
",ap);
        for(int i=0;i<ap;i++)printf("%d
",as[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5469179.html