版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82785094
传送门:bzoj4259
题解
带通配符的字符串匹配无法有效地用 处理,这时大常数的 派上了用场。
这题已经升级为一种套路/模板了,暂且引用ebola’s题解的称呼:带通配符的单模式串匹配。
设模式串为 ,文本串为 。“*”对应0, 分别对应 。
为便于叙述和进行FFT,设字符串下标均从0开始。
假设在
中以
位置结尾的长度为
的子串能匹配上
,则:
分别表示其中有串当前位为通配符的情况。
对应字母相同的情况。
至于取差的平方,相当于是取绝对值,这样保证了和为0的情况一定是完全匹配的(考虑如果没有取差的平方而是取了差, 和 就完全匹配了)。
设 串翻转后得到 ,则 可以转变为卷积的形式:
所以设表示答案的多项式为 ,当 以位置 结尾的子串完全匹配 时, ,否则 。
能够发现实际上
等价于
,将
展开:
做7遍 即可。
代码
#include<bits/stdc++.h>
#define db double
#define RI register
using namespace std;
const int N=1e6+10,M=3e5+2;
const db pi=acos(-1);
int n,m,L,len,rv[N],ans[M],tot,A[M],B[M];
char s[2][M];
struct cc{
db r,i;
cc(){r=i=0;};
cc(db r_,db i_){r=r_;i=i_;}
cc operator +(const cc&ky){return cc(r+ky.r,i+ky.i);}
cc operator -(const cc&ky){return cc(r-ky.r,i-ky.i);}
cc operator *(const cc&ky){return cc(r*ky.r-i*ky.i,r*ky.i+i*ky.r);}
cc operator /(const int&ky){return cc(r/(db)ky,i/(db)ky);}
inline cc conj(){return cc(r,-i);}
}a[N],b[N],f[N];
inline void FFT(cc *e,int ptr)
{
RI int i,j,k;cc bs,ori,ix,iy;
for(i=1;i<len;++i) if(i<rv[i]) swap(e[i],e[rv[i]]);
for(i=1;i<len;i<<=1){
ori=cc(cos(pi/i),ptr*sin(pi/i));
for(j=0;j<len;j+=(i<<1)){
bs=cc(1,0);
for(k=0;k<i;++k,bs=bs*ori){
ix=e[j+k];iy=bs*e[i+j+k];
e[j+k]=ix+iy;e[i+j+k]=ix-iy;
}
}
}
if(ptr==1) return;
for(i=0;i<len;++i) e[i]=e[i]/len;
}
int main(){
RI int i,j,k,t;
scanf("%d%d%s%s",&m,&n,s[0],s[1]);
for(i=0;i<m;++i) A[m-1-i]= s[0][i]=='*'?0:(s[0][i]-'a'+1);
for(i=0;i<n;++i) B[i]= s[1][i]=='*'?0:(s[1][i]-'a'+1);
len=1;L=0;
for(;len<=n;len<<=1) L++;
for(i=1;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(L-1));
for(i=0;i<len;++i) a[i]=b[i]=cc(0,0);
for(i=0;i<m;++i) a[i].r=A[i]*A[i]*A[i];
for(i=0;i<n;++i) b[i].r=B[i];
FFT(a,1);FFT(b,1);
for(i=0;i<len;++i) f[i]=a[i]*b[i];
for(i=0;i<len;++i) a[i]=b[i]=cc(0,0);
for(i=0;i<m;++i) a[i].r=A[i];
for(i=0;i<n;++i) b[i].r=B[i]*B[i]*B[i];
FFT(a,1);FFT(b,1);
for(i=0;i<len;++i) f[i]=f[i]+a[i]*b[i];
for(i=0;i<len;++i) a[i]=b[i]=cc(0,0);
for(i=0;i<m;++i) a[i].r=A[i]*A[i];
for(i=0;i<n;++i) b[i].r=B[i]*B[i];
FFT(a,1);FFT(b,1);
for(i=0;i<len;++i) f[i]=f[i]-a[i]*b[i]*cc(2,0);
FFT(f,-1);
for(i=m-1;i<n;++i)
if(int(f[i].r+0.5)==0)
ans[tot++]=i+2-m;
printf("%d\n",tot);
for(i=0;i<tot;++i) printf("%d ",ans[i]);
return 0;
}