1. 程式人生 > >[CF528D]Fuzzy Search

[CF528D]Fuzzy Search

位置 http ans scanf sea pla mark code cst

luogu

sol

這種字符串匹配的問題顯然可以把一個串\(reverse\)過來然後用\(FFT\)做吧。
對每種字母分開考慮,設兩個多項式\(A(x),B(x)\),其中
\[A(x)=\sum_{i=0}^{n-1}[區間[i-k,i+k]內存在該種字符]x^i\]
\[B(x)=\sum_{i=0}^{n-1}[t[i]為該種字符]x^i\]
然後兩個多項式卷一下就是這種字符在第\(i\)個位置上的匹配吧。
最後對每次的系數求和,若恰好等於\(|T|\)則說明匹配成功。
復雜度\(O(4n\log n)\)

code

#include<cstdio>
#include<algorithm>
#include<cmath> using namespace std; const int _ = 8e5+5; const double Pi = acos(-1); struct Complex{ double rl,im; Complex(){rl=im=0;} Complex(double a,double b){rl=a,im=b;} Complex operator + (Complex b) {return Complex(rl+b.rl,im+b.im);} Complex operator - (Complex b) {return
Complex(rl-b.rl,im-b.im);} Complex operator * (Complex b) {return Complex(rl*b.rl-im*b.im,rl*b.im+im*b.rl);} }w[_],a[_],b[_]; int N,n,m,k,rev[_],l,tmp[_],ans[_],Ans; char s[_],t[_],fg[4]={'A','G','C','T'}; void FFT(Complex *P,int opt) { for (int i=0;i<N;++i) if
(i<rev[i]) swap(P[i],P[rev[i]]); for (int i=1;i<N;i<<=1) for (int p=i<<1,j=0;j<N;j+=p) for (int k=0;k<i;++k) { Complex W=w[N/i*k];W.im*=opt; Complex X=P[j+k],Y=W*P[j+k+i]; P[j+k]=X+Y;P[j+k+i]=X-Y; } if (opt==-1) for (int i=0;i<N;++i) P[i].rl/=N; } int main() { scanf("%d%d%d",&n,&m,&k);scanf("%s%s",s,t);reverse(t,t+m); for (N=1;N<n+m;N<<=1) ++l;--l; for (int i=0;i<N;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l); for (int i=0;i<N;++i) w[i]=Complex(cos(Pi*i/N),sin(Pi*i/N)); for (int zsy=0;zsy<4;++zsy) { for (int i=0;i<N;++i) a[i].rl=a[i].im=b[i].rl=b[i].im=0; for (int i=0,pos=-1e9;i<n;++i) { if (s[i]==fg[zsy]) pos=i; if (pos>=i-k) a[i].rl=1; } for (int i=n-1,pos=1e9;~i;--i) { if (s[i]==fg[zsy]) pos=i; if (pos<=i+k) a[i].rl=1; } for (int i=0;i<m;++i) if (t[i]==fg[zsy]) b[i].rl=1; FFT(a,1);FFT(b,1); for (int i=0;i<N;++i) a[i]=a[i]*b[i]; FFT(a,-1); for (int i=0;i<n;++i) ans[i]+=(int)(a[i].rl+0.5); } for (int i=0;i<n;++i) if (ans[i]==m) ++Ans; printf("%d\n",Ans);return 0; }

[CF528D]Fuzzy Search