题面描述:S、T两个串,求出T在S中出现了几次。其中T中有'?'可以匹配任意字符。S长度n不超过10^5,T长度m不超过S长度。
乍一看因该是个关于字符串处理的题目,然后我就杯具了。。。。
果断滚粗去看题解,这居然是到FFT!
先把T字符串翻转,定义 c[j+m-1] = sigma( (a[j+i]-b[m-1-i])^2 * a[j+i] * b[m-1-i] )(0<=i<m)
其中定义 字符’?‘的值为0,'a'~’z'为1~26,a为S的权值数组,b为T的权值数组。
那么如果c[j+m-1]=0,那么S[j~j+m-1]与T匹配,否则不匹配。
直接求c数组复杂度是O(nm),如何快速求c数组?
将式子展开得 c[j+m-1] = sigma( a[j+i]^3*b[m-1-i] ) + sigma( a[j+i]*b[m-1-i]^3 ) - 2*sigma( a[j+i]^2*b[m-1-i]^2 )
每一个可以发现这其实是个卷积,对于每个Sigma里用FFT求一下即可,复杂度O(nlogn)
(蒟蒻被虐得爽爽的)
//吐槽:stl里的complex确实好慢。。。老老实实的手写去了
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int Maxn=400005; #define sqr(a) ((a)*(a)) #define cube(a) ((a)*(a)*(a)) typedef long long LL; int n,m,N,M,i,j,k,cnt,rev[Maxn],dig[20]; LL ans[Maxn]; char S[Maxn],T[Maxn]; struct CP { double X,Y; CP operator +(const CP &a){ return (CP){X+a.X,Y+a.Y}; } CP operator -(const CP &a){ return (CP){X-a.X,Y-a.Y}; } CP operator *(const CP &a){ return (CP){X*a.X-Y*a.Y,X*a.Y+Y*a.X}; } } a[Maxn],b[Maxn]; void FFT(CP a[],int flag){ for (i=0;i<N;i++) if (i<rev[i]) swap(a[i],a[rev[i]]); for (i=2;i<=N;i<<=1){ CP wn = (CP) { cos(2*M_PI/i), flag*sin(2*M_PI/i) }; for (j=0;j<N;j+=i){ CP w = (CP) {1,0}; for (k=j;k<j+i/2;k++){ CP x=a[k], y=a[k+i/2]*w; a[k]=x+y; a[k+i/2]=x-y; w=w*wn; } } } if (flag==1) return; for (i=0;i<N;i++) a[i].X/=N; } void calc(LL flag){ FFT(a,1); FFT(b,1); for (i=0;i<N;i++) a[i]=a[i]*b[i]; FFT(a,-1); for (i=m-1;i<m-1+n;i++) ans[i-m+1]+=flag * (LL) (a[i].X+0.5); } int main(){ freopen("match.in","r",stdin); freopen("match.out","w",stdout); scanf("%s",S); n=strlen(S); scanf("%s",T); m=strlen(T); for (i=0;i+i<m-1;i++) swap(T[i],T[m-1-i]); for (N=2, M=1;N<(n+m);N<<=1, M++); for (i=0;i<N;i++){ int len=0; for (j=i;j>0;j>>=1) dig[len++]=(j&1); for (j=0;j<M;j++) rev[i]=( (rev[i]<<1)|dig[j] ); } // a^3*b for (i=0;i<n;i++) {a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0}; a[i].X=cube(a[i].X);} for (i=n;i<N;i++) a[i]=(CP){0,0}; for (i=0;i<m;i++) b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0}; for (i=m;i<N;i++) b[i]=(CP){0,0}; calc(1); //a*b^3 for (i=0;i<n;i++) a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0};; for (i=n;i<N;i++) a[i]=(CP){0,0}; for (i=0;i<m;i++) {b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0}; b[i].X=cube(b[i].X);} for (i=m;i<N;i++) b[i]=(CP){0,0}; calc(1); //a^2*b^2 for (i=0;i<n;i++) {a[i]=(CP){S[i]!='?'?S[i]-'a'+1:0, 0};; a[i].X=sqr(a[i].X);} for (i=n;i<N;i++) a[i]=(CP){0,0}; for (i=0;i<m;i++) {b[i]=(CP){ T[i]!='?'?T[i]-'a'+1:0, 0}; b[i].X=sqr(b[i].X);} for (i=m;i<N;i++) b[i]=(CP){0,0}; calc(-2); for (i=0;i<=n-m;i++) if (ans[i]==0) cnt++; printf("%d\n",cnt); for (i=0;i<=n-m;i++) if (ans[i]==0) printf("%d\n",i); return 0; }