如果我们把*看成
0
,两个串相等当且仅当
答案要求的就是对于每个
t
,
将
A
翻转,
对三项卷积分别FFT即可。
为了卡常数,最后可以把三个东西加起来再IDFT,一共要做 7 <script type="math/tex" id="MathJax-Element-7">7</script>次DFT。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1100000;
const double pi=acos(-1);
int n,m,r[maxn],len,bit;
char s[maxn];
bool ok[maxn];
struct cd
{
double r,i;
cd(){r=i=0;}
cd(double xr,double xi){r=xr;i=xi;}
cd operator +(cd a){return (cd){r+a.r,i+a.i};}
cd operator -(cd a){return (cd){r-a.r,i-a.i};}
cd operator *(cd a){return (cd){r*a.r-i*a.i,i*a.r+r*a.i};}
cd operator *(double d){return (cd){r*d,i*d};}
}a_1[maxn],b_1[maxn],a_2[maxn],b_2[maxn],a_3[maxn],b_3[maxn],ans[maxn];
void init()
{
for(len=1;len<2*n;bit++,len<<=1);
for(int i=0;i<len;i++)
r[i]=(r[i>>1]>>1)|((i&1)<<(bit-1));
}
void fft(cd *a,int n,int dft)
{
for(int i=0;i<n;i++)
if(i<r[i]) swap(a[i],a[r[i]]);
int j,k;
for(int i=1;i<n;i<<=1){
cd wnk(cos(pi/i),sin(pi/i)*dft);
for(int j=0;j<n;j+=(i<<1)){
cd wk(1,0);
for(int k=j;k<i+j;k++,wk=wk*wnk){
cd x=a[k],y=wk*a[k+i];
a[k]=x+y;a[k+i]=x-y;
}
}
}
if(dft==-1) for(int i=0;i<n;i++) a[i]=a[i]*(1.0/n);
}
int main()
{
scanf("%d%d%s",&m,&n,s);
for(int i=0;i<m;i++)
a_1[m-1-i].r=(s[i]=='*'?0:s[i]-'a'+1);
for(int i=0;i<m;i++)
a_2[i]=a_1[i]*a_1[i],a_3[i]=a_2[i]*a_1[i];
scanf("%s",s);
for(int i=0;i<n;i++)
b_1[i].r=(s[i]=='*'?0:s[i]-'a'+1);
for(int i=0;i<n;i++)
b_2[i]=b_1[i]*b_1[i],b_3[i]=b_2[i]*b_1[i];
init();
fft(a_1,len,1);
fft(b_1,len,1);
fft(a_2,len,1);
fft(b_2,len,1);
fft(a_3,len,1);
fft(b_3,len,1);
for(int i=0;i<len;i++)
ans[i]=a_1[i]*b_3[i]-a_2[i]*b_2[i]*2+a_3[i]*b_1[i];
fft(ans,len,-1);
int cnt=0;
for(int i=m-1;i<n;i++) if(abs(ans[i].r)<1e-2) ok[i-m+2]=1,cnt++;
printf("%d\n",cnt);
for(int i=1;i<=n-m+1;i++) if(ok[i]) printf("%d ",i);
return 0;
}