CF528D Fuzzy Search 字符串匹配+FFT
阿新 • • 發佈:2019-02-23
alt 有一個 size out swap ble 陌生 cal main
題意:
DNA序列,在母串s中匹配模式串t,對於s中每個位置i,只要s[i-k]到s[i+k]中有c就認為匹配了c。求有多少個位置匹配了t。
分析:
這個字符串匹配的方式,什麽kmp,各種自動機都不靈。
所以有一個邪門功夫,fft字符串匹配。(做過洛谷《殘缺的字符串》一題的應該都不陌生,帶通配符的匹配字符串可以用fft卷積來做)
首先,由於字符集大小只有4,所以我們可以對每個字符分別考慮。
根據題意,對於每個字符,我們預處理a[i]數組,代表i位置是否能匹配當前字符(左右k個能匹配也算)
之後b[i]數組,保存t[i]位置的字符是不是c。
然後將b數組倒過來,fft做一下卷積,把答案累計起來檢查總和是不是m就可以判斷是否匹配。
代碼:
1 #include<bits/stdc++.h> 2 #define db double 3 #define cp complex<db> 4 using namespace std; 5 const int N=530005; 6 const db pi=acos(-1); 7 int ans,ton[N],n,m,k,lm,L,r[N]; 8 char s[N],t[N];cp a[N],b[N]; 9 void init(){ 10 scanf("%d%d%d%s%s",&n,&m,&k,s,t); 11 } voidfft字符串匹配fft(cp *f,int op){ 12 for(int i=0;i<lm;i++) 13 if(i>r[i]) swap(f[i],f[r[i]]); 14 for(int l=1;l<lm;l<<=1){ 15 cp wn(cos(pi/l),op*sin(pi/l)); 16 for(int i=0;i<lm;i+=(l<<1)){ 17 cp w(1,0); 18 for(int j=0;j<l;j++,w*=wn){ 19 cp T=w*f[i+j+l];20 f[i+j+l]=f[i+j]-T;f[i+j]+=T; 21 } 22 } 23 } if(op==-1) for(int i=0;i<lm;i++) f[i]/=lm; 24 } void calc(char c){ 25 memset(a,0,sizeof(a));memset(b,0,sizeof(b)); 26 int cnt=0; 27 for(int i=0;i<k;i++) cnt+=(s[i]==c); 28 for(int i=0;i<n;i++){ 29 if(i+k<n) cnt+=(s[i+k]==c); 30 if(i-k-1>=0) cnt-=(s[i-k-1]==c); 31 a[i]=cnt>0?1:0;cout<<a[i]<<" "; 32 } for(int i=0;i<m;i++) b[i]=(t[i]==c);puts(""); 33 fft(a,1);fft(b,1); 34 for(int i=0;i<lm;i++) a[i]*=b[i]; 35 fft(a,-1);for(int i=0;i<=n-m;i++) 36 ton[i]+=(int)(a[i+m-1].real()+0.5); 37 } void solve(){ 38 for(lm=1;lm<=n+m-2;lm<<=1,L++); 39 for(int i=0;i<lm;i++) 40 r[i]=(r[i>>1]>>1)|((i&1)<<(L-1)); 41 reverse(t,t+m);calc(‘A‘); 42 calc(‘G‘);calc(‘C‘);calc(‘T‘); 43 for(int i=0;i<=n-m;i++) if(ton[i]==m) ans++; 44 printf("%d\n",ans); 45 } int main(){ 46 init();solve();return 0; 47 }
CF528D Fuzzy Search 字符串匹配+FFT