给定串\(S\),以及带通配符的串\(T\),询问\(T\)在\(S\)中出现了几回。而且输出对应的位置。ios
\(|S|,|T|<=10^5\),字符集大小为\(26\)函数
先来考虑没有通配符怎么匹配。别跟我说KMP!!spa
根据前面几个题目的套路,咱们能够把每一个字符分开来考虑,而后将\(T\)串反转,将有这个字符的位置变成\(1\),而后\(FFT\),就能够知道在这一段里面这个字符匹配上了多少个,而后把每一个字符求个和,检查是否刚好匹配了\(|T|\)个。code
通配符此时并不须要考虑。string
时间复杂度\(O(26nlogn)\)it
固然,若是您真的这么写了,那么确定\(T\)飞了。\(FFT\)自带巨大常数。对于字符集很小的时候上述方法是可行的,字符集很大的时候就不能这么作了。io
因此咱们考虑如何只作一遍\(FFT\)。(没有通配符的状况下)class
每一个字符固然不能动了,因此把他们对应成数字。若是匹配上了怎么办?那就是上下两个对应的数字相等,能够考虑做差。可是又发现做差可能会使得几个正数和几个负数相加变成\(0\),因此考虑平方。stream
因此,咱们定义每一个位置的函数值\(f(x)=\sum_{i=1}^{|T|}(S[x+i-1]-T[i])^2\)map
将\(T\)串反转,平方项拆开以后,就变成了两个卷积+一个常数项的形式,直接\(FFT\)而后求和,检查最后的函数值是否为\(0\)就好了。
如今有了通配符,咱们不妨令\(a..z\)对应的数字为\(1..26\)。通配符不管给它一个什么数字,它和上面的字符的差的平方必定不为\(0\)。
因此咱们换种方法考虑,把通配符对应的数字设为\(0\),可是这样差的平方不是\(0\),因此咱们就在上面那个式子后面乘上一个\(T[i]\)的权值,若是此时是通配符就会乘\(0\),从而也变成了\(0\)。这样一来,原来的式子就变成了\(f(x)=\sum_{i=1}^{|T|}(S[x+i-1]-T[i])^2T[i]\)
拆开后是两个卷积+一个常数项的形式,\(FFT\)便可。
时间复杂度\(O(nlogn)\)
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAX 333333 const double Pi=acos(-1); struct Complex{double a,b;}A1[MAX],B1[MAX],A2[MAX],B2[MAX],W[MAX],F[MAX]; Complex operator+(Complex a,Complex b){return (Complex){a.a+b.a,a.b+b.b};} Complex operator-(Complex a,Complex b){return (Complex){a.a-b.a,a.b-b.b};} Complex operator*(Complex a,Complex b){return (Complex){a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a};} int n,m,r[MAX],N,Z; int pos[MAX],ans,l; char S[MAX],T[MAX]; void FFT(Complex *P,int opt) { for(int i=1;i<N;++i)if(i<r[i])swap(P[i],P[r[i]]); for(int i=1;i<N;i<<=1) for(int p=i<<1,j=0;j<N;j+=p) for(int k=0;k<i;++k) { Complex w=(Complex){W[N/i*k].a,W[N/i*k].b*opt}; Complex X=P[j+k],Y=w*P[j+k+i]; P[j+k]=X+Y;P[i+j+k]=X-Y; } if(opt==-1)for(int i=0;i<N;++i)P[i].a/=N; } int main() { scanf("%s",S);scanf("%s",T); n=strlen(S);m=strlen(T); for(N=1;N<=(n+m-2);N<<=1)++l; for(int i=0;i<N;++i)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); for(int i=1;i<N;i<<=1) for(int k=0;k<i;++k)W[N/i*k]=(Complex){cos(k*Pi/i),sin(k*Pi/i)}; for(int i=0;i<n;++i)A1[i].a=(S[i]-96)*(S[i]-96),A2[i].a=2*(S[i]-96); for(int i=0;i<m;++i) { int x=((T[m-i-1]=='?')?0:(T[m-i-1]-96)); B1[i].a=x;B2[i].a=x*x;Z+=x*x*x; } FFT(A1,1);FFT(B1,1);FFT(A2,1);FFT(B2,1); for(int i=0;i<N;++i) F[i]=A1[i]*B1[i]-A2[i]*B2[i]; FFT(F,-1); for(int i=m-1;i<n;++i) if((int)(F[i].a+0.5+Z)==0)pos[++ans]=i-m+1; printf("%d\n",ans); for(int i=1;i<=ans;++i)printf("%d\n",pos[i]); return 0; }