1. 程式人生 > >51nod 1565模糊搜索(FFT)

51nod 1565模糊搜索(FFT)

cout can ans ace mes 一個 style std tdi

題目大意就是字符串匹配,不過有一個門限k而已

之前有提到過fft做字符串匹配,這裏和之前那種有些許不同

因為只有A,C,G,T四種字符,所以就考慮構造4個01序列

例如,模板串a關於‘A‘的01序列中,1代表這個位置可以匹配,而0則代表不能匹配。

這樣構造出4個序列後,再對匹配串b做同樣的處理

下面用a[‘A‘]代表a關於‘A‘的01序列,b同理

然後可以知道a[‘A‘][i]&b[‘A‘][i]如果是1則代表可以匹配,如果是0則代表不能匹配。

那麽在位置i兩個串能否匹配就可以寫做

for(x = i ~ i+lenb) ans += a[‘A‘][i]&b[‘A‘][i]

如果ans恰好等於b中‘A‘的個數,那麽就說明‘A‘匹配成功,接下來做‘C‘,‘G‘,‘T‘的情況

如果都可以匹配成功,那麽這個位置就可以匹配了

如何用fft做這個呢?實際上也很簡單

把b串顛倒一下就變成了a[‘A‘][i]&b[‘A‘][lenb-i]

就是一個卷積形式,於是就可以fft了

(測試感覺stl裏的complex比較慢,非遞歸比遞歸快很多)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <bitset>
#include <cmath>
#include <complex>
using namespace std;
const double pi = acos(-1); const int maxn = 800050; int A[4][maxn], B[4][maxn], ANS[maxn]; struct cp { double a,b; cp() { a = b = 0; } cp(double _a, double _b):a(_a), b(_b) {} cp operator+(const cp&y)const { return cp(a+y.a, b+y.b); } cp operator-(const cp&y)const { return cp(a-y.a, b-y.b); } cp
operator*(const cp&y)const { return cp(a*y.a-b*y.b,a*y.b+b*y.a); } cp operator!()const { return cp(a,-b); } }; int T[128]; int la, lb, k; char str[maxn]; class FFT { int n, L, R[maxn]; cp a[maxn], b[maxn]; void DFT(cp *a,int n,int f) { for(int i = 0; i < n; i++) if(i < R[i]) swap(a[i], a[R[i]]); for(int i = 1; i < n; i <<= 1) { cp t, x, wn(cos(pi/i), sin(pi*f/i)); for(int j = 0; j < n; j += (i<<1)) { cp w(1, 0); for(int k = 0; k < i; k++,w = w*wn) { x = a[j+k]; t = w*a[j+k+i]; a[j+k] = x+t; a[j+k+i] = x-t; } } } } public: int c[maxn]; FFT() { memset(R, 0, sizeof(R)); } void init(int *A, int *B, int n1, int n2) { memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); for(int i = 0; i <= n1; i++) a[i] = cp(A[i], 0); for(int i = 0; i <= n2; i++) b[i] = cp(B[i], 0); n2 += n1; for(n = 1, L = 0; n <= n2; n <<= 1) L++; for(int i = 0; i < n; i++) R[i] = (R[i>>1]>>1)|((i&1)<<(L-1)); } void calc() { DFT(a, n, 1); DFT(b, n, 1); for(int i = 0; i <= n; i++) a[i] = a[i]*b[i]; DFT(a, n, -1); for(int i = 0; i <= n; i++) c[i] = (a[i].a/n + 0.5); } } fft; int main() { cin>>la>>lb>>k; T[A] = 0; T[C] = 1; T[G] = 2; T[T] = 3; scanf("%s", str); for(int i = 0; i < la; i++) { int ty = T[str[i]]; A[ty][i] = 1; for(int j = i+1; j <= min(i+k, la-1); j++) { if(ty == T[str[j]]) break; A[ty][j] = 1; } for(int j = i-1; j >= max(0, i-k); j--) { if(A[ty][j]) break; A[ty][j] = 1; } } scanf("%s", str); for(int i = 0; i < lb; i++) { int ty = T[str[i]]; B[ty][lb-i-1] = 1; } for(int i = lb-1; i <= la+lb-2; i++) ANS[i] = 1; for(int i = 0; i < 4; i++) { fft.init(A[i], B[i], la, lb); fft.calc(); int t = 0; for(int j = 0; j < lb; j++) if(B[i][j]) t++; for(int j = lb-1; j <= la+lb-2; j++) ANS[j] &= (fft.c[j] == t); } int ans = 0; for(int i = lb-1; i <= la+lb-2; i++) ans += ANS[i]; cout<<ans<<endl; }

51nod 1565模糊搜索(FFT)