Description
Input
Output
Sample Input
a?aba?abba
Sample Output
HINT
Source
分析:
我们定义两个长度均为n的字符串的距离(字符串的不同程度)为:
dis=∑n−1i=0(s1[i]−s2[i])2 d i s = ∑ i = 0 n − 1 ( s 1 [ i ] − s 2 [ i ] ) 2
因为 s2 s 2 中存在通配字符 “?” “ ? ” ,所以我们把 “?” “ ? ” 的值设为0,这样距离的计算公式就变成了:
dis=∑n−1i=0s1[i]s2[i]∗(s1[i]−s2[i])2
d
i
s
=
∑
i
=
0
n
−
1
s
1
[
i
]
s
2
[
i
]
∗
(
s
1
[
i
]
−
s
2
[
i
]
)
2
当且仅当dis=0的时候,两字符串相等
事先声明一下:这道题需要用FFT优化
所以我们需要寻找卷积的形式
因为题目给出的S和T的长度不一样,我们可以枚举第一个串匹配结束位置
定义函数:
fk=∑m−1i=0S[k−m+1+i]T[i]∗(S[k−m+1+i]−T[i])2 f k = ∑ i = 0 m − 1 S [ k − m + 1 + i ] T [ i ] ∗ ( S [ k − m + 1 + i ] − T [ i ] ) 2
其中,第一个串匹配结束位置为k,m为第二串的长度
当且仅当
fk=0
f
k
=
0
的时候表明匹配成功了
那么我们就从第一位开始比对
我们观察一下卷积的形式:
Cn=∑n−1i=0aibn−i
C
n
=
∑
i
=
0
n
−
1
a
i
b
n
−
i
可以看到,a和b的下标之和是一个定值
我们可以把T翻转:
这样S和T比对位置就符合卷积的形式了:
fk=∑m−1i=0S[k−m+1+i]T[m−1−i]∗(S[k−m+1+i]−T[m−1−i])2 f k = ∑ i = 0 m − 1 S [ k − m + 1 + i ] T [ m − 1 − i ] ∗ ( S [ k − m + 1 + i ] − T [ m − 1 − i ] ) 2
S的下标实在太复杂了
为了简化下标,但是我们可以在
T
T
后面添加很多个0,让ta变成一个枚举的式子
fk=∑ki=0S[i]T[k−i]∗(S[i]−T[k−i])2 f k = ∑ i = 0 k S [ i ] T [ k − i ] ∗ ( S [ i ] − T [ k − i ] ) 2
fk=∑n−1i=0S[i]3T[k−i]−2∗S[i]2T[k−i]2+S[i]T[k−i]3 f k = ∑ i = 0 n − 1 S [ i ] 3 T [ k − i ] − 2 ∗ S [ i ] 2 T [ k − i ] 2 + S [ i ] T [ k − i ] 3
因为只有T中有 “?” “ ? ” ,所以我们可以少乘一个S[i]
fk=∑n−1i=0S[i]2T[k−i]−2∗S[i]T[k−i]2+T[k−i]3 f k = ∑ i = 0 n − 1 S [ i ] 2 T [ k − i ] − 2 ∗ S [ i ] T [ k − i ] 2 + T [ k − i ] 3
我们针对每一部分计算卷积,相加即可
Q.
为什么卷积可以完成比对的任务呢?
我们不是应该以S的每一个字符为起点进行比对吗?
A.
想一下卷积是干什么用的:多项式乘法
也就是说,
A∗B
A
∗
B
,
A
A
的每一个位置都会乘上的第
i
i
位
这就相当于以的每一位置为比对起点进行比对
tip
FFT只是用来计算这样的式子的:
S[i]T[n−i]
S
[
i
]
T
[
n
−
i
]
至于
S[i]2
S
[
i
]
2
这样的,直接
S[i]∗S[i]
S
[
i
]
∗
S
[
i
]
注意最后一部分
T[n−i]3
T
[
n
−
i
]
3
,也是一个卷积形式:
T[n−i]3∗1
T
[
n
−
i
]
3
∗
1
注意我们枚举的是匹配结束的位置
为了保险,所有的范围都设为fn
对于a和b的赋值不要偷懒只改x
#include<bits/stdc++.h>
using namespace std;
const double pi=acos(-1.0);
const int N=500005;
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,s[N],t[N],ans[N];
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 S[N>>2],T[N>>2];
int get(char c) {
if (c>='a'&&c<='z') return c-'a'+1;
else return 0;
}
int main()
{
scanf("%s",S);
scanf("%s",T);
n=strlen(S);
m=strlen(T);
for (int i=0;i<n;i++) s[i]=get(S[i]);
for (int i=0;i<m;i++) t[m-i-1]=get(T[i]);
fn=1;
while (fn<=n+m) fn<<=1;
init(fn);
for (int i=0;i<fn;i++) a[i]=node(s[i]*s[i],0);
for (int i=0;i<fn;i++) b[i]=node(t[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*s[i],0);
for (int i=0;i<fn;i++) b[i]=node(t[i]*t[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(1.0,0);
for (int i=0;i<fn;i++) b[i]=node(t[i]*t[i]*t[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);
ans[0]=0;
for (int i=0;i<=n-m;i++)
if (c[i+m-1].x/fn<0.5) ans[++ans[0]]=i; //i+m-1 匹配结尾
printf("%d\n",ans[0]);
for (int i=1;i<=ans[0];i++) printf("%d\n",ans[i]);
return 0;
}