Description
Input
Output
Sample Input
a*b
aebr*ob
Sample Output
1 5
HINT
Source
分析:
毒瘤Claris!
我要写出最好的题解
首先我们要需要一个东西来判断两个字符串是否相等
设
dis(A,B)
d
i
s
(
A
,
B
)
表示字符串
A
A
和的差异程度(假设
A
A
和的长度相等为
n
n
)
由于字符串中存在通配字符,所以我们把 “∗” “ ∗ ” 的价值设为0,并且更改一下 dis d i s 的表达式:
dis(A,B)=∑n−1i=0AiBi(Ai−Bi)2 d i s ( A , B ) = ∑ i = 0 n − 1 A i B i ( A i − B i ) 2
由题目给出的数据范围可以看出,
B
B
串较长
所以我们可以枚举串中匹配结束的点
i
i
设计函数:
当且仅当
fi=0
f
i
=
0
时,两字符串相等
上面这个式子很像卷积,然而仅仅是像而已
我们能不能把ta构造成一个卷积的形式呢? 答案是肯定的
观察一下卷积的定义式:
ck=∑ni=0aibk−i
c
k
=
∑
i
=
0
n
a
i
b
k
−
i
a,b
a
,
b
的下标之和是一个定值
我们在字符串匹配的时候,从第一位开始:
如果我们把第二个字符串翻转一下:
就可以发现,
A
A
和的比对位置相加是一个定值,符合卷积的形式了
fi=dis(A,B[i−m+1,i])=∑m−1j=0Am−1−jBi−m+1+j(Am−1−j−Bi−m+1+j)2 f i = d i s ( A , B [ i − m + 1 , i ] ) = ∑ j = 0 m − 1 A m − 1 − j B i − m + 1 + j ( A m − 1 − j − B i − m + 1 + j ) 2
B的下标实在太复杂了
为了简化下标,但是我们可以在A后面添加很多个0,让ta变成一个枚举i的式子
(意会一下就可以了)
fi=∑m−1j=0AjBi−j(Aj−Bi−j)2 f i = ∑ j = 0 m − 1 A j B i − j ( A j − B i − j ) 2
fi=∑m−1j=0A3jBi−j−2A2jB2i−j+AjB3i−j f i = ∑ j = 0 m − 1 A j 3 B i − j − 2 A j 2 B i − j 2 + A j B i − j 3
上式的三个部分都是卷积的形式
对于形如
A3j
A
j
3
的部分,直接
Aj∗Aj∗Aj
A
j
∗
A
j
∗
A
j
即可(因为下标都相等,并不是卷积,只是最简单的乘法)
我们将三个部分分别计算卷积,相加即可
因为我们枚举的是
B
B
串中匹配结束的点
如果
fi=0
f
i
=
0
,那么匹配起点是
i−m+1
i
−
m
+
1
Q.
为什么卷积可以完成匹配的任务呢?
我们不是应该枚举
B
B
的每一个字符吗?
A.
想一下卷积是干什么用的:多项式乘法
也就是说,,
B
B
的每一个位置都会乘上的第
i
i
位
这就相当于以的每一位置为匹配起点进行匹配
tip
数组的大小都是
fn
f
n
(大于n+m最小二的整数幂)
对于
a
a
和的赋值不要偷懒只改
x
x
<script type="math/tex" id="MathJax-Element-6645">x</script>
#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
const double pi=acos(-1.0);
struct node{
double x,y;
node (double xx=0,double yy=0) {
x=xx;y=yy;
}
};
node a[N],b[N],c[N],o[N],_o[N];
int n,m,fn,ans[N>>1];
node operator +(const node &a,const node &b) {return node(a.x+b.x,a.y+b.y);}
node operator -(const node &a,const node &b) {return node(a.x-b.x,a.y-b.y);}
node operator *(const node &a,const node &b) {return node(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
void init(int n) {
for (int i=0;i<n;i++) {
o[i]=node(cos(2.0*i*pi/n),sin(2.0*i*pi/n));
_o[i]=node(cos(2.0*i*pi/n),-sin(2.0*i*pi/n));
}
}
void FFT(int n,node *a,node *w) {
int i,j=0,k;
for (i=0;i<n;i++) {
if (i>j) swap(a[i],a[j]);
for (int l=n>>1;(j^=l)<l;l>>=1);
}
for (i=2;i<=n;i<<=1) {
int m=i>>1;
for (j=0;j<n;j+=i)
for (k=0;k<m;k++) {
node z=a[j+m+k]*w[n/i*k];
a[j+m+k]=a[j+k]-z;
a[j+k]=a[j+k]+z;
}
}
}
char A[300010],B[300010];
int s1[N],s2[N];
int get(char x) {
if (x>='a'&&x<='z') return x-'a'+1;
else return 0;
}
int main() {
scanf("%d%d",&m,&n);
scanf("%s",A);
scanf("%s",B);
for (int i=0;i<m;i++) s1[m-1-i]=get(A[i]);
for (int i=0;i<n;i++) s2[i]=get(B[i]);
fn=1;
while (fn<=n+m) fn<<=1;
init(fn);
for (int i=0;i<fn;i++) a[i]=node(s1[i]*s1[i]*s1[i],0);
for (int i=0;i<fn;i++) b[i]=node(s2[i],0);
FFT(fn,a,o);
FFT(fn,b,o);
for (int i=0;i<fn;i++) c[i]=a[i]*b[i];
for (int i=0;i<fn;i++) a[i]=node(2.0*s1[i]*s1[i],0);
for (int i=0;i<fn;i++) b[i]=node(s2[i]*s2[i],0);
FFT(fn,a,o);
FFT(fn,b,o);
for (int i=0;i<fn;i++) c[i]=c[i]-a[i]*b[i];
for (int i=0;i<fn;i++) a[i]=node(s1[i],0);
for (int i=0;i<fn;i++) b[i]=node(s2[i]*s2[i]*s2[i],0);
FFT(fn,a,o);
FFT(fn,b,o);
for (int i=0;i<fn;i++) c[i]=c[i]+a[i]*b[i];
FFT(fn,c,_o);
int cnt=0;
for (int i=0;i<=n-m;i++)
if (c[i+m-1].x/fn<0.5) ans[++cnt]=i+1;
printf("%d\n",cnt);
for (int i=1;i<=cnt;i++) printf("%d ",ans[i]);
return 0;
}