FFT~
终于有一道能自己写出来的FFT了……好感动……
其实就是上一道的简化版,用sum{(a[i]-b[j])^2*b[j]}==0来记录两串相符,把式子拆开后发现是三次卷积,然后把b串翻转一下FFT就可以了~
区分n,nn,mm!
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> using namespace std; #define pi acos(-1) #define N 100001 #define M 400010 int n,nn,mm,l,r[M],ans[M]; double a[N],b[N]; char s[N]; struct E{ double r,i; E (double u,double v) {r=u;i=v;} E () {} E operator + (E u) {return E(r+u.r,i+u.i);} E operator - (E u) {return E(r-u.r,i-u.i);} E operator * (E u) {return E(r*u.r-i*u.i,r*u.i+i*u.r);} }f1[M],f2[M],c[M]; E operator / (E u,int v) {return E(u.r/v,u.i/v);} void fft(E *u,int v) { for(int i=0;i<n;i++) if(i<r[i]) swap(u[i],u[r[i]]); for(int i=1;i<n;i<<=1) { E wn(cos(pi/i),v*sin(pi/i)); for(int j=0;j<n;j+=(i<<1)) { E w(1,0); for(int k=0;k<i;k++,w=w*wn) { E x=u[j+k],y=w*u[i+j+k]; u[j+k]=x+y;u[i+j+k]=x-y; } } } if(v==-1) for(int i=0;i<n;i++) u[i]=u[i]/n; } int main() { scanf("%s",s);nn=strlen(s); for(int i=0;i<nn;i++) a[i]=(double)s[i]-'a'+1; scanf("%s",s);mm=strlen(s); for(int i=0;i<mm;i++) b[i]=s[mm-i-1]=='?' ? (double)0:(double)s[mm-i-1]-'a'+1; for(n=1;n<2*nn;n<<=1) l++; for(int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); for(int i=0;i<nn;i++) f1[i].r=a[i]*a[i],f2[i].r=b[i]; fft(f1,1);fft(f2,1); for(int i=0;i<n;i++) c[i]=f1[i]*f2[i]; for(int i=0;i<n;i++) f1[i].r=f1[i].i=f2[i].r=f2[i].i=0; for(int i=0;i<nn;i++) f1[i].r=a[i],f2[i].r=b[i]*b[i]; fft(f1,1);fft(f2,1); for(int i=0;i<n;i++) c[i]=c[i]-f1[i]*f2[i]-f1[i]*f2[i]; for(int i=0;i<n;i++) f1[i].r=f1[i].i=f2[i].r=f2[i].i=0; for(int i=0;i<nn;i++) f1[i].r=(double)1,f2[i].r=b[i]*b[i]*b[i]; fft(f1,1);fft(f2,1); for(int i=0;i<n;i++) c[i]=c[i]+f1[i]*f2[i]; fft(c,-1); for(int i=mm-1;i<nn;i++) if(fabs(c[i].r)<0.5) ans[++ans[0]]=i-mm+1; for(int i=0;i<=ans[0];i++) printf("%d\n",ans[i]); return 0; }