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\n",ap); for(int i=0;i<ap;i++)printf("%d\n",as[i]); } return 0; }