解析
通配符匹配的经典题。
设单词串为
A
A
A,文章串为
B
B
B。
把
A
A
A 翻转一下,判断问题就能转化为一个卷积的形式:
F
(
p
)
=
&
i
=
0
m
−
1
m
a
t
c
h
(
A
i
+
1
,
B
p
−
i
)
F(p)=\&_{i=0}^{m-1}match(A_{i+1},B_{p-i})
F(p)=&i=0m−1match(Ai+1,Bp−i)
m
a
t
c
h
(
a
,
b
)
match(a,b)
match(a,b) 表示
a
,
b
a,b
a,b 两个字符是否互相匹配。
但是这么丑的东西显然难以优化,我们需要更优美的表达形式。
考虑且运算的性质,我们需要一个非法就能检测出非法,那么我们考虑利用平方的非负性,设计一个函数
C
(
a
,
b
)
=
(
a
−
b
)
2
C(a,b)=(a-b)^2
C(a,b)=(a−b)2,把函数改写成:
F
(
p
)
=
∑
i
=
0
m
−
1
C
(
A
i
+
1
,
B
p
−
i
)
F(p)=\sum_{i=0}^{m-1}C(A_{i+1},B_{p-i})
F(p)=i=0∑m−1C(Ai+1,Bp−i)
位置合法当且仅当对应函数值为0,把平方拆开分别算再加起来即可。
现在考虑如何加入通配符。
只要
a
,
b
a,b
a,b 中有任意一个是通配符,就应该是合法的。
利用
0
0
0 乘任何数都是
0
0
0 的性质,对于
C
C
C 函数进行微调:
C
(
a
,
b
)
=
(
a
−
b
)
2
j
d
(
a
)
j
d
(
b
)
C(a,b)=(a-b)^2jd(a)jd(b)
C(a,b)=(a−b)2jd(a)jd(b)
其中
j
d
(
a
)
jd(a)
jd(a) 表示字符
a
a
a 是否不是 *
。
这样就可以卷起来算了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read() {
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=2e6+100;
const int mod=998244353;
int n,m,k;
inline ll ksm(ll x,ll k){
ll res=1;
while(k){
if(k&1) res=res*x%mod;
x=x*x%mod;k>>=1;
}
return res;
}
int r[N];
void init(int n,int &lim){
lim=1;int L=0;
while(lim<n) lim<<=1,L++;
for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
}
void NTT(ll *x,int lim,int op){
for(int i=0;i<lim;i++) if(i<r[i]) swap(x[i],x[r[i]]);
for(int l=1;l<lim;l<<=1){
ll w=ksm(3,(mod-1)/(l<<1));if(op==-1) w=ksm(w,mod-2);
for(int st=0;st<lim;st+=(l<<1)){
for(ll i=0,now=1;i<l;i++,now=now*w%mod){
ll u=x[st+i],v=now*x[st+i+l]%mod;
x[st+i]=u+v>=mod?u+v-mod:u+v;
x[st+i+l]=u-v<0?u-v+mod:u-v;
}
}
}
if(op==-1){
ll ni=ksm(lim,mod-2);
for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;
}
return;
}
void copy(ll *a,ll *b,int n,int lim){
assert(n<=lim);
memcpy(a,b,sizeof(ll)*n);
fill(a+n,a+lim,0);return;
}
void mul(ll *a,ll *b,ll *c,int n,int m){
static ll u[N],v[N];
static int lim;
//for(int i=0;i<n;i++) printf("%lld ",a[i]);putchar('\n');
//for(int i=0;i<m;i++) printf("%lld ",b[i]);putchar('\n');
init(n+m-1,lim);
copy(u,a,n,lim);
copy(v,b,m,lim);
NTT(u,lim,1);NTT(v,lim,1);
for(int i=0;i<lim;i++) c[i]=u[i]*v[i]%mod;
NTT(c,lim,-1);
//for(int i=0;i<n+m-1;i++) printf("%lld ",c[i]);putchar('\n');
//putchar('\n');
return;
}
void inv(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
if(n==1){
f[0]=ksm(h[0],mod-2);return;
}
inv(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
copy(t1,f,n,lim);copy(t2,h,n,lim);
NTT(t1,lim,1);NTT(t2,lim,1);
for(int i=0;i<lim;i++) t1[i]=(2*t1[i]-t1[i]*t1[i]%mod*t2[i]%mod+mod)%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
//499122177
void Sqrt(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
if(n==1){
f[0]=1;return;
}
Sqrt(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
inv(f,t1,n);
fill(t1+n,t1+lim,0);
mul(h,t1,t1,n,n);
copy(t2,f,n,lim);
NTT(t1,lim,1);NTT(t2,lim,1);
for(int i=0;i<lim;i++) t1[i]=(t1[i]+t2[i]%mod)*499122177%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
void dao(ll *h,ll *f,int n){
static ll t[N];
static int lim;
init(n<<1,lim);
copy(t,h,n,lim);
f[n-1]=0;
for(int i=0;i<n-1;i++) f[i]=t[i+1]*(i+1)%mod;
fill(f+n,f+lim,0);
return;
}
void jifen(ll *h,ll *f,int n){
static ll t[N];
static int lim;
init(n<<1,lim);
copy(t,h,n,lim);
f[0]=0;
for(int i=1;i<n;i++) f[i]=h[i-1]*ksm(i,mod-2)%mod;
fill(f+n,f+lim,0);
}
void Ln(ll *h,ll *f,int n){
static ll t1[N],t2[N];
static int lim;
init(n<<1,lim);
inv(h,t1,n);
fill(t1+n,t1+lim,0);
dao(h,t2,n);
mul(t1,t2,t1,n,n);
jifen(t1,f,n);
return;
}
void Exp(ll *h,ll *f,int n){
static ll t1[N],t2[N],t3[N];
static int lim;
if(n==1){
f[0]=1;return;
}
Exp(h,f,(n+1)>>1);
init(n<<1,lim);
fill(f+((n+1)>>1),f+lim,0);
copy(t1,f,n,lim);
copy(t2,h,n,lim);
Ln(f,t3,n);fill(t3+n,t3+lim,0);
NTT(t1,lim,1);NTT(t2,lim,1);NTT(t3,lim,1);
for(int i=0;i<lim;i++) t1[i]=t1[i]*(1+t2[i]-t3[i]+mod)%mod;
NTT(t1,lim,-1);
memcpy(f,t1,sizeof(ll)*n);
return;
}
ll a[N],b[N],c[N],res[N];
bool x[N],y[N];
char s1[N],s2[N];
int ans[N],tot;
signed main() {
#ifndef ONLINE_JUDGE
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
#endif
//printf("%d\n",sizeof(a1)/1024/1024);
m=read();n=read();
scanf(" %s %s",s1+1,s2+1);
for(int l=1,r=m;l<r;l++,r--) swap(s1[l],s1[r]);
for(int i=1;i<=m;i++) x[i]=(s1[i]!='*'),s1[i]-='a'-1;
for(int i=1;i<=n;i++) y[i]=(s2[i]!='*'),s2[i]-='a'-1;
for(int i=1;i<=m;i++) a[i]=s1[i]*s1[i]*x[i];
for(int i=1;i<=n;i++) b[i]=y[i];
mul(a,b,c,m+1,n+1);
for(int i=1;i<=n+1;i++) res[i]+=c[i];
for(int i=1;i<=m;i++) a[i]=x[i];
for(int i=1;i<=n;i++) b[i]=s2[i]*s2[i]*y[i];
mul(a,b,c,m+1,n+1);
for(int i=1;i<=n+1;i++) res[i]+=c[i];
for(int i=1;i<=m;i++) a[i]=s1[i]*x[i];
for(int i=1;i<=n;i++) b[i]=s2[i]*y[i];
mul(a,b,c,m+1,n+1);
for(int i=1;i<=n+1;i++) res[i]-=2*c[i];
for(int p=m;p<=n;p++) if(res[p+1]==0) ans[++tot]=p-m+1;
printf("%d\n",tot);
for(int i=1;i<=tot;i++) printf("%d ",ans[i]);
return 0;
}
/*
4
0 1 1
*/