BZOJ4259:残缺的字符串(FFT)
Description
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
Input
第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
第二行为一个长度为m的字符串A。
第三行为一个长度为n的字符串B。
两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。
Output
第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。
Sample Input
3 7
a*b
aebr*ob
a*b
aebr*ob
Sample Output
2
1 5
1 5
Solution
FFT好神啊还能做字符串的题(逃
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #define N (1200000+1000) 6 using namespace std; 7 8 double pi=acos(-1.0),F[N]; 9 int n,m,fn,l,r[N],A[N],B[N]; 10 int ans_num,ans[N]; 11 char stA[N],stB[N]; 12 struct complex 13 { 14 double x,y; 15 complex (double xx=0,double yy=0) 16 { 17 x=xx; y=yy; 18 } 19 }a[N],b[N]; 20 21 complex operator + (complex a,complex b){return complex(a.x+b.x,a.y+b.y);} 22 complex operator - (complex a,complex b){return complex(a.x-b.x,a.y-b.y);} 23 complex operator * (complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} 24 complex operator / (complex a,double b){return complex(a.x/b,a.y/b);} 25 26 void FFT(int n,complex *a,int opt) 27 { 28 for (int i=0; i<n; ++i) 29 if (i<r[i]) 30 swap(a[i],a[r[i]]); 31 for (int k=1; k<n; k<<=1) 32 { 33 complex wn=complex(cos(pi/k),opt*sin(pi/k)); 34 for (int i=0; i<n; i+=k<<1) 35 { 36 complex w=complex(1,0); 37 for (int j=0; j<k; ++j,w=w*wn) 38 { 39 complex x=a[i+j], y=w*a[i+j+k]; 40 a[i+j]=x+y; a[i+j+k]=x-y; 41 } 42 } 43 } 44 if (opt==-1) for (int i=0; i<n; ++i) a[i]=a[i]/n; 45 } 46 47 int main() 48 { 49 scanf("%d%d",&m,&n); 50 scanf("%s%s",stA+1,stB+1); 51 for (int i=1; i<=m; ++i) A[m-i+1]=(stA[i]=='*')?0:stA[i]-'a'+1; 52 for (int i=1; i<=n; ++i) B[i]=(stB[i]=='*')?0:stB[i]-'a'+1; 53 m++; n++;//因为我是字符串AB都向右移了一位,则计算出来的答案应该是向右移动两位的,故这里要+1 54 55 fn=1; 56 while (fn<=n+m) fn<<=1,l++; 57 for (int i=0; i<fn; ++i) 58 r[i]=(r[i>>1]>>1) | ((i&1)<<(l-1)); 59 60 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 61 for (int i=1; i<=n; ++i) 62 a[i].x=A[i]*A[i]*A[i],b[i].x=B[i]; 63 FFT(fn,a,1); FFT(fn,b,1); 64 for (int i=0; i<=fn; ++i) 65 a[i]=a[i]*b[i]; 66 FFT(fn,a,-1); 67 for (int i=1; i<=n; ++i) 68 F[i]+=a[i].x; 69 70 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 71 for (int i=1; i<=n; ++i) 72 a[i].x=A[i]*A[i],b[i].x=B[i]*B[i]; 73 FFT(fn,a,1); FFT(fn,b,1); 74 for (int i=0; i<=fn; ++i) 75 a[i]=a[i]*b[i]; 76 FFT(fn,a,-1); 77 for (int i=1; i<=n; ++i) 78 F[i]-=2*a[i].x; 79 80 memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); 81 for (int i=1; i<=n; ++i) 82 a[i].x=A[i],b[i].x=B[i]*B[i]*B[i]; 83 FFT(fn,a,1); FFT(fn,b,1); 84 for (int i=0; i<=fn; ++i) 85 a[i]=a[i]*b[i]; 86 FFT(fn,a,-1); 87 for (int i=1; i<=n; ++i) 88 F[i]+=a[i].x; 89 90 for (int i=m; i<=n; ++i) if ((int)(F[i]+0.5)==0) ans[++ans_num]=i-m+1; 91 printf("%d\n",ans_num); 92 for (int i=1; i<ans_num; ++i) printf("%d ",ans[i]); 93 printf("%d",ans[ans_num]); 94 }