权限题
题意:
有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。这两个串已经老化了,每个串都有不同程度的残缺。
你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?
1<=m<=n<=300000 1 <= m <= n <= 300000
Solution:
神奇的FFT解决字符串问题….
我们把 ∗ ∗ 看成0,定义一个两个长度相等的串之间的距离为:
这样的话如果 dis(a,b)==0 d i s ( a , b ) == 0 ,那就说明a和b相等
为什么不能用 dis(a,b)=∑leni=1(a[i]−b[i])∗a[i]∗b[i] d i s ( a , b ) = ∑ i = 1 l e n ( a [ i ] − b [ i ] ) ∗ a [ i ] ∗ b [ i ] 呢?因为这样可能出现一个正数一个负数相加正好=0的情况
我们定义f [i] [ i ] 为 dis(a,b[i−m+1,i]) d i s ( a , b [ i − m + 1 , i ] )
那么 f[i]=∑m−1j=0(a[j]−b[j+i−m+1])2∗a[j]∗b[j+i−m+1] f [ i ] = ∑ j = 0 m − 1 ( a [ j ] − b [ j + i − m + 1 ] ) 2 ∗ a [ j ] ∗ b [ j + i − m + 1 ]
发现这个东西很像多项式乘法的样子
我们翻转A串,并在后面补0至与B串等长
那么f[i]变为: f[i]=∑ij=0(a[j]−b[i−j])2∗a[j]∗b[i−j] f [ i ] = ∑ j = 0 i ( a [ j ] − b [ i − j ] ) 2 ∗ a [ j ] ∗ b [ i − j ]
=∑ij=0(a[j]2−2∗a[j]∗b[i−j]+b[i−j]2)∗a[j]∗b[i−j] = ∑ j = 0 i ( a [ j ] 2 − 2 ∗ a [ j ] ∗ b [ i − j ] + b [ i − j ] 2 ) ∗ a [ j ] ∗ b [ i − j ]
=∑ij=0(a[j]3∗b[i−j]−2∗a[j]2∗b[i−j]2+a[j]∗b[i−j]3) = ∑ j = 0 i ( a [ j ] 3 ∗ b [ i − j ] − 2 ∗ a [ j ] 2 ∗ b [ i − j ] 2 + a [ j ] ∗ b [ i − j ] 3 )
然后做3遍FFT就好啦
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1048580;
int n,m,len;
char s1[N],s2[N];
const double pi=acos(-1);
struct complex{
double x,y;
complex(double _x=0.0,double _y=0.0)
{
x=_x,y=_y;
}
complex operator +(const complex &b)const
{
return complex(x+b.x,y+b.y);
}
complex operator -(const complex &b)const
{
return complex(x-b.x,y-b.y);
}
complex operator *(const complex &b)const
{
return complex(x*b.x-y*b.y,y*b.x+x*b.y);
}
}a[N],b[N],c[N];
void change(complex y[],int len)
{
int i,j,k;
for (i=1,j=len/2;i<len-1;i++)
{
if (i<j) swap(y[i],y[j]);
k=len/2;
while (j>=k) j-=k,k>>=1;
if (j<k) j+=k;
}
}
void fft(complex y[],int len,int ifi)
{
change(y,len);
for (int h=2;h<=len;h<<=1)
{
complex wn(cos(2*ifi*pi/h),sin(2*ifi*pi/h));
for (int i=0;i<len;i+=h)
{
complex w(1,0);
for (int j=i;j<i+h/2;j++)
{
complex u=y[j];
complex v=w*y[j+h/2];
y[j]=u+v;y[j+h/2]=u-v;
w=w*wn;
}
}
}
if (ifi==-1) for (int i=0;i<len;i++) y[i].x/=len;
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s1);scanf("%s",s2);
for (int l=0,r=n-1;l<r;l++,r--) swap(s1[l],s1[r]);
len=1;
while (len<2*m) len<<=1;
for (int i=0;i<n;i++) if (s1[i]=='*') a[i]=complex(0,0);else a[i]=complex((s1[i]-'a'+1)*(s1[i]-'a'+1)*(s1[i]-'a'+1),0);
for (int i=n;i<len;i++) a[i]=complex(0,0);
for (int i=0;i<m;i++) if (s2[i]=='*') b[i]=complex(0,0);else b[i]=complex((s2[i]-'a'+1),0);
for (int i=m;i<len;i++) b[i]=complex(0,0);
fft(a,len,1);fft(b,len,1);for (int i=0;i<len;i++) c[i]=c[i]+a[i]*b[i];
for (int i=0;i<n;i++) if (s1[i]=='*') a[i]=complex(0,0);else a[i]=complex((s1[i]-'a'+1)*(s1[i]-'a'+1),0);
for (int i=n;i<len;i++) a[i]=complex(0,0);
for (int i=0;i<m;i++) if (s2[i]=='*') b[i]=complex(0,0);else b[i]=complex((s2[i]-'a'+1)*(s2[i]-'a'+1),0);
for (int i=m;i<len;i++) b[i]=complex(0,0);
fft(a,len,1);fft(b,len,1);for (int i=0;i<len;i++) c[i]=c[i]-complex(2,0)*a[i]*b[i];
for (int i=0;i<n;i++) if (s1[i]=='*') a[i]=complex(0,0);else a[i]=complex((s1[i]-'a'+1),0);
for (int i=n;i<len;i++) a[i]=complex(0,0);
for (int i=0;i<m;i++) if (s2[i]=='*') b[i]=complex(0,0);else b[i]=complex((s2[i]-'a'+1)*(s2[i]-'a'+1)*(s2[i]-'a'+1),0);
for (int i=m;i<len;i++) b[i]=complex(0,0);
fft(a,len,1);fft(b,len,1);for (int i=0;i<len;i++) c[i]=c[i]+a[i]*b[i];
fft(c,len,-1);
int ans=0;
for (int i=n-1;i<m;i++)
if (c[i].x<0.5) ans++;
printf("%d\n",ans);
for (int i=n-1;i<m;i++)
if (c[i].x<0.5) printf("%d ",i-n+2);
}