BZOJ4259:残缺的字符串——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4259
很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
跟随胡神犇的步伐先把前置技能学了。
参考:https://www.cnblogs.com/clrs97/p/4814499.html
kmp是不行的,而作为一道套路题,我们有一定的套路:暴力匹配!
先默认字符串是以0开头的,方便我们后来FFT。
设dis(A,B)=(A-B)*[A!='*']*[B!='*']表示了AB字符是否相等,如果相等则答案为0。
于是我们把*字符看做0,则直接变成dis(A,B)=(A-B)AB。
设f[i]为B串以i为终点,往前与A匹配是否能匹配上。
显然就是dis累加的过程,只要最终f[i]=0就说明i-n+2是一个合法解。
然后你就会发现这个dis累加拆开之后很像卷积啊。
于是把A数组倒过来然后后面补齐0(即*字符),你就会发现实际上这就是三个卷积。
于是我们(不)愉快的写了个FFT并且AC。
(式子推导就看参考吧……心情不好不想写数学公式)
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef double dl; const dl pi=acos(-1.0); const dl eps=0.5; const int N=2e6+5; struct complex{ dl x,y; complex(dl xx=0.0,dl yy=0.0){ x=xx;y=yy; } complex operator +(const complex &b)const{ return complex(x+b.x,y+b.y); } complex operator -(const complex &b)const{ return complex(x-b.x,y-b.y); } complex operator *(const complex &b)const{ return complex(x*b.x-y*b.y,x*b.y+y*b.x); } }; void FFT(complex a[],int n,int on){ for(int i=1,j=n>>1;i<n-1;i++){ if(i<j)swap(a[i],a[j]); int k=n>>1; while(j>=k){j-=k;k>>=1;} if(j<k)j+=k; } for(int i=2;i<=n;i<<=1){ complex res(cos(-on*2*pi/i),sin(-on*2*pi/i)); for(int j=0;j<n;j+=i){ complex w(1,0); for(int k=j;k<j+i/2;k++){ complex u=a[k],t=w*a[k+i/2]; a[k]=u+t;a[k+i/2]=u-t; w=w*res; } } } if(on==-1) for(int i=0;i<n;i++)a[i].x/=n; } int n,m,a[N],b[N]; complex f[N],A[N],B[N]; char s1[N],s2[N]; int main(){ scanf("%d%d%s%s",&n,&m,s1,s2); for(int i=0,j=n-1;i<j;i++,j--)swap(s1[i],s1[j]); for(int i=0;i<n;i++){ if(s1[i]!='*')a[i]=s1[i]-'a'+1; else a[i]=0; } for(int i=0;i<m;i++){ if(s2[i]!='*')b[i]=s2[i]-'a'+1; else b[i]=0; } int len=1; while(len<m)len<<=1; for(int i=0;i<len;i++) A[i]=complex(a[i]*a[i]*a[i],0),B[i]=complex(b[i],0); FFT(A,len,1);FFT(B,len,1); for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i]; for(int i=0;i<len;i++) A[i]=complex(a[i]*a[i],0),B[i]=complex(b[i]*b[i],0); FFT(A,len,1);FFT(B,len,1); for(int i=0;i<len;i++)f[i]=f[i]-A[i]*B[i]*complex(2,0); for(int i=0;i<len;i++) A[i]=complex(a[i],0),B[i]=complex(b[i]*b[i]*b[i],0); FFT(A,len,1);FFT(B,len,1); for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i]; FFT(f,len,-1); int ans=0; for(int i=n-1;i<m;i++)if(f[i].x<eps)ans++; printf("%d\n",ans); if(ans){ for(int i=n-1;i<m;i++)if(f[i].x<eps)printf("%d ",i-n+2); puts(""); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++