Link
Description
给你两个串 A A A和 B B B,长度分别为 m m m和 n n n
要求你输出 B B B的每一个能和 A A A完全匹配的位置
关键是两个串里都有通配符
1 ≤ m ≤ n ≤ 3 ∗ 1 0 5 1\le m \le n\le 3*10^5 1≤m≤n≤3∗105
Solution
表示我完全不会这题,太神啦Orz
我们定义两个字符串的距离函数:
KaTeX parse error: Expected 'EOF', got '\*' at position 46: …t{!=}B_i][A_i!=\̲*̲][B_i!= \* ]
这样两个字符串能匹配当且仅当他们的距离函数值为0
我们可以为每个字符设置对应的值,例如: ∗ = 0 , a = 1 , b = 2 , . . . , z = 26 *=0,a=1,b=2,...,z=26 ∗=0,a=1,b=2,...,z=26
这样距离函数就可以这样去描述:
d i s ( A , B ) = ∑ i = 0 n ( A i − B i ) 2 A i B i dis(A,B)=\sum_{i=0}^n(A_i-B_i)^2A_iB_i dis(A,B)=∑i=0n(Ai−Bi)2AiBi
这样变得十分简洁,也方便处理。
那么如果
A
A
A和
B
[
r
−
m
+
1
,
r
]
B[r-m+1,r]
B[r−m+1,r]匹配的话,可以这样描述:
d
i
s
(
A
,
B
[
r
−
m
+
1
,
r
]
)
=
∑
i
=
0
m
−
1
(
A
i
−
B
r
−
m
+
i
+
1
)
2
A
i
B
r
−
m
+
i
+
1
=
0
dis(A,B[r-m+1,r])=\sum_{i=0}^{m-1} (A_i-B_{r-m+i+1})^2A_iB_{r-m+i+1}=0
dis(A,B[r−m+1,r])=i=0∑m−1(Ai−Br−m+i+1)2AiBr−m+i+1=0
我们发现,只要把
A
A
A倒过来并且补0直到与
B
B
B等长,并且定义那个距离函数叫
f
r
f_r
fr,那么上面的式子可以改写为:
f
r
=
∑
i
=
0
r
(
A
i
−
B
r
−
i
)
2
A
i
B
r
−
i
=
∑
i
=
0
r
A
i
3
B
r
−
i
−
2
∑
i
=
0
r
A
i
2
B
r
−
i
2
+
∑
i
=
0
r
A
i
B
r
−
i
3
f_r=\sum_{i=0}^{r}(A_i-B_{r-i})^2A_iB_{r-i} \\ =\sum_{i=0}^r A_i^3B_{r-i}-2\sum_{i=0}^r A_i^2 B_{r-i}^2+\sum_{i=0}^r A_iB_{r-i}^3
fr=i=0∑r(Ai−Br−i)2AiBr−i=i=0∑rAi3Br−i−2i=0∑rAi2Br−i2+i=0∑rAiBr−i3
非常明显,我们只要卷积一下就可以得出所有
f
r
f_r
fr的取值了
当然这里要分三段卷积,一共7次 F F T FFT FFT
时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=3e5+5,M=1e6+1e5+5;
const double pi=acos(-1);
struct cp{
double r,i;
cp(){}
cp(double _r,double _i):r(_r),i(_i){}
inline cp operator + (const cp& b) const {return cp(r+b.r,i+b.i);}
inline cp operator - (const cp& b) const {return cp(r-b.r,i-b.i);}
inline cp operator * (const cp& b) const {return cp(r*b.r-i*b.i,r*b.i+i*b.r);}
inline cp operator * (double b) const {return cp(r*b,i*b);}
}A1[M],B1[M],A2[M],B2[M],A3[M],B3[M];
int m,n,L,len,R[M];
char a[N],b[N];
inline void FFT(cp *a,int n,int f){
for(int i=0;i<n;++i)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
for(int i=0;i<n;++i)if(i<R[i])swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1){
cp wn(cos(pi/i),f*sin(pi/i));
for(int j=0;j<n;j+=(i<<1)){
cp w(1,0);
for(int k=0;k<i;++k,w=w*wn){
cp x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y;a[j+k+i]=x-y;
}
}
}
if(f==-1)for(int i=0;i<n;++i)a[i].r/=n;
}
int main(){
m=read();n=read();
scanf("%s",a);
scanf("%s",b);
if(m>n){
printf("0\n");
return 0;
}
for(int i=0;i<m;++i){
int x=a[m-i-1]-'a'+1;
if(a[m-i-1]=='*')x=0;
A1[i].r=x;
A2[i].r=x*x;
A3[i].r=x*x*x;
}
for(int i=0;i<n;++i){
int x=b[i]-'a'+1;
if(b[i]=='*')x=0;
B1[i].r=x;
B2[i].r=x*x;
B3[i].r=x*x*x;
}
for(len=1;len<(n<<1);len<<=1)L++;
FFT(A1,len,1);FFT(A2,len,1);FFT(A3,len,1);
FFT(B1,len,1);FFT(B2,len,1);FFT(B3,len,1);
for(int i=0;i<len;++i)
A1[i]=A1[i]*B3[i]+A3[i]*B1[i]-A2[i]*B2[i]*2;
FFT(A1,len,-1);
int cnt=0;
for(int i=m-1;i<n;++i)if(A1[i].r<0.5)cnt++;
printf("%d\n",cnt);
for(int i=m-1;i<n;++i)if(A1[i].r<0.5)printf("%d ",i-m+2);
putchar('\n');
return 0;
}