【BZOJ4503】两个串 FFT
【BZOJ4503】两个串
Description
兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。
Input
两行两个字符串,分别代表S和T
Output
第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。
Sample Input
bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
a?aba?abba
a?aba?abba
Sample Output
0
HINT
S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”
题解:同【BZOJ4259】残缺的字符串
不过这里不需要外面在乘一个Si+j,所以少了一项,直接计算出来就行
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #define pi acos(-1.0) using namespace std; struct cp { double x,y; cp (double a,double b){x=a,y=b;} cp (){} cp operator + (cp a){return cp(x+a.x,y+a.y);} cp operator - (cp a){return cp(x-a.x,y-a.y);} cp operator * (cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);} }n1[1<<20],n2[1<<20],n3[1<<20],n4[1<<20]; int s[1<<20],t[1<<20]; int ans[1<<20],sta[1<<20]; int l1,l2,top,n5; char s1[1<<20],s2[1<<20]; void FFT(cp *a,int len,int f) { int i,j,k,h; cp t; for(i=k=0;i<len;i++) { if(i>k) swap(a[i],a[k]); for(j=(len>>1);(k^=j)<j;j>>=1); } for(h=2;h<=len;h<<=1) { cp wn(cos(f*2*pi/h),sin(f*2*pi/h)); for(j=0;j<len;j+=h) { cp w(1,0); for(k=j;k<j+h/2;k++) t=w*a[k+h/2],a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn; } } } int main() { int i,j,len=1; scanf("%s%s",s1,s2),l1=strlen(s1),l2=strlen(s2); while(len<l1+2*l2) len<<=1; for(i=0;i<l1;i++) s[i]=s1[i]-'a'+1; for(i=0;i<l2;i++) t[l2-i-1]=(s2[i]=='?')?0:(s2[i]-'a'+1); for(i=0;i<l1;i++) n1[i]=cp(1.0*s[i]*s[i],0.0),n3[i]=cp(2.0*s[i],0.0); for(i=0;i<l2;i++) n2[i]=cp(1.0*t[i],0.0),n4[i]=cp(1.0*t[i]*t[i],0.0); FFT(n1,len,1),FFT(n2,len,1),FFT(n3,len,1),FFT(n4,len,1); for(i=0;i<len;i++) n1[i]=n1[i]*n2[i]-n3[i]*n4[i]; FFT(n1,len,-1); for(i=0;i<l2;i++) n5+=t[i]*t[i]*t[i]; for(i=0;i<l1-l2+1;i++) if(!(int)(n1[i+l2-1].x/len+n5+0.5)) sta[++top]=i; printf("%d\n",top); for(i=1;i<=top;i++) printf("%d\n",sta[i]); return 0; }
| 欢迎来原网站坐坐! >原文链接<