Description
兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。
Input
两行两个字符串,分别代表S和T
Output
第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。
Sample Input
bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
a?aba?abba
Sample Output
0
HINT
S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”
这题酷似kmp,但是由于有通配符”?”的存在,所以并不能用。
那么可以把“匹配”这个概念转化为
(c1−c2)2=0
因为有通配符的存在
c2(c1−c2)2=0
那么子串匹配也就是求
∑lenT−1j=0Tj(Si−Tj)2=0
把这个式子展开来
∑lenT−1j=0Tj(S2i−2SiTj+T2j)=0
∑lenT−1j=0TjS2i−2SiT2j+T3j=0
其实
i
可以表示成
∑lenT−1j=0TjS2j+x−2Sj+xT2j+T3j=0
进而
∑lenT−1j=0TjS2j+x−∑lenT−1j=02Sj+xT2j+∑lenT−1j=0T3j=0
最后一个我们暂时不用去管,先看前面两个。
因为卷积满足函数的下标和不变,但是这两个是差不变,那么我们考虑把其中一个函数反转,使其满足卷积下标和不变的性质。
令
T′i=TlenT−i−1
∑lenT−1j=0TlenT−j−1S2j+x−∑lenT−1j=02Sj+xT2lenT−j−1+∑lenT−1j=0T3lenT−j−1=0
然后我们再发现
lenT−j−1+j+x=lenT+x−1≠lenT−1
但事实上,这是等效的,因为
lenT−1
~
lenT+x−1
的这一段我们都可以把它看作0。
那么三次fft求解即可
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long LL;
const int maxn=110000;
const double pi=acos(-1.0);
struct complex
{
double r,i;
complex() {}
complex(double _r,double _i) {r=_r,i=_i;}
friend complex operator + (const complex &x,const complex &y) {return complex(x.r+y.r,x.i+y.i);}
friend complex operator - (const complex &x,const complex &y) {return complex(x.r-y.r,x.i-y.i); }
friend complex operator * (const complex &x,const complex &y) {return complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
} a[maxn*4],b[maxn*4],c[maxn*4];
int R[maxn*4];
void fft(complex *y,int len,int on)
{
for(int i=0; i<len; i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=1; i<len; i<<=1)
{
complex wn(cos(pi/i),sin(on*pi/i));
for(int j=0; j<len; j+=(i<<1))
{
complex w(1,0);
for(int k=0; k<i; k++,w=w*wn)
{
complex u=y[j+k];
complex v=w*y[j+k+i];
y[j+k]=u+v;
y[j+k+i]=u-v;
}
}
}
if(on==-1)for(int i=0; i<len; i++)y[i].r/=len;
}
inline int get(char c)
{
if(c>='a' && c<='z') return c-'a'+1;
else return 0;
}
char s1[maxn*4],s2[maxn*4];
int S[maxn*4],T[maxn*4];
int main()
{
int lenS,lenT;
scanf("%s",s1);
lenS=strlen(s1);
for(int i=0; i<lenS; i++) S[i]=get(s1[i]);
scanf("%s",s2);
lenT=strlen(s2);
for(int i=0; i<lenT; i++) T[i]=get(s2[lenT-i-1]);
int m=lenS+lenT,n,L=0;
for(n=1; n<=m; n*=2) L++;
for(int i=0; i<n; i++) R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
for(int i=0; i<n; i++) a[i]=complex(S[i]*S[i],0);
for(int i=0; i<n; i++) b[i]=complex(T[i],0);
fft(a,n,1);
fft(b,n,1);
for(int i=0; i<n; i++) c[i]=c[i]+a[i]*b[i];
for(int i=0; i<n; i++) a[i]=complex(1,0);
for(int i=0; i<n; i++) b[i]=complex(T[i]*T[i]*T[i],0);
fft(a,n,1);
fft(b,n,1);
for(int i=0; i<n; i++) c[i]=c[i]+a[i]*b[i];
for(int i=0; i<n; i++) a[i]=complex(S[i]*2,0);
for(int i=0; i<n; i++) b[i]=complex(T[i]*T[i],0);
fft(a,n,1);
fft(b,n,1);
for(int i=0; i<n; i++) c[i]=c[i]-a[i]*b[i];
fft(c,n,-1);
int ans=0;
for(int i=0; i<lenS-lenT+1; i++) if(c[i+lenT-1].r<0.5) ans++;
printf("%d\n",ans);
for(int i=0; i<lenS-lenT+1; i++) if(c[i+lenT-1].r<0.5) printf("%d\n",i);
return 0;
}