bzoj 4503 两个串
Description
兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,
分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。
Input
两行两个字符串,分别代表S和T
Output
第一行一个正整数k,表示T在S中出现了几次
接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。
Sample Input
ababcadaca
a?a
a?a
Sample Output
3
0
5
0
5
HINT
S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”
将b串反转
设两个串的距离值为∑(ai-aj)2aiaj=∑ai3aj+∑aiaj3-∑2ai2aj2
当为*时ai为0
FFT直接上
#include<bits/stdc++.h> #define pi acos(-1) #define maxn 300010 using namespace std; struct Complex{ double r,i; Complex(double x=0,double y=0){r=x,i=y;} Complex operator + (Complex x){return Complex(r+x.r,i+x.i);} Complex operator - (Complex x){return Complex(r-x.r,i-x.i);} Complex operator * (Complex x){return Complex(r*x.r-i*x.i,r*x.i+i*x.r);} }A[maxn],B[maxn],C[maxn]; char a[maxn],b[maxn]; int rev[maxn]; int N,L; int k1[maxn],k2[maxn]; int l1,l2; int ans; int k[maxn]; void FFT(Complex a[],int n,int f){ for(int i=0;i<n;++i) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int i=2;i<=n;i<<=1){ Complex wn=Complex(cos(2*pi/i),sin(2*pi/i)*f); for(int j=0;j<n;j+=i){ Complex w=Complex(1,0); for(int k=0;k<(i>>1);++k,w=w*wn){ Complex tmp1=a[j+k],tmp2=a[j+k+(i>>1)]*w; a[j+k]=tmp1+tmp2;a[j+k+(i>>1)]=tmp1-tmp2; } } } if(f==-1)for(int i=0;i<n;++i)a[i].r/=n; } void init(){ scanf("%s%s",a,b); l1=strlen(a);l2=strlen(b); for(int i=0;i<l1;++i)k1[i]=a[i]-'a'+1; for(int i=0;i<(l2>>1);++i)swap(b[i],b[l2-i-1]); for(int i=0;i<l2;++i) if(b[i]=='?')k2[i]=0; else k2[i]=b[i]-'a'+1; N=1,L=0;while(N<l1+l2)N<<=1,L++; for(int i=0;i<N;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); } void work(){ for(int i=0;i<N;++i)A[i]=Complex(k1[i],0); for(int i=0;i<N;++i)B[i]=Complex(k2[i]*k2[i]*k2[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(k1[i]*k1[i]*k1[i],0); for(int i=0;i<N;++i)B[i]=Complex(k2[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(k1[i]*k1[i]*2,0); for(int i=0;i<N;++i)B[i]=Complex(k2[i]*k2[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); for(int i=l2-1;i<l1;++i) if(C[i].r<0.5)k[++ans]=i-l2+1; printf("%d\n",ans); for(int i=1;i<=ans;++i) printf("%d\n",k[i]); } int main(){ init(); work(); return 0; }