「题解」Codeforces 528D Fuzzy Search
分别仅考虑 \(A,C,G,T\),把匹配成功的位置取个交集就可以。
使用 FFT 来完成字符串匹配。
现在仅考虑 \(A\),把 \(S\) 中不会和 \(A\) 匹配上的位置上的字符设为 \(o\),把 \(T\) 中不是 \(A\) 的字符设为 \(\#\),则匹配函数 \(C(x,y)\) (其中 \(x\) 来自 \(S\),\(y\) 来自 \(T\))要满足:
- \(=0,x=A,y=A\);
- \(=0,x=A,y=\#\);
- \(>0,x=o,y=A\);
- \(=0,x=o,y=\#\).
这样的 \(C\) 才能满足匹配成功值为 \(0\),否则大于 \(0\).
设:
-
\(S\) 中的 \(A\) 值为 \(0\),\(o\) 值为 \(1\);
-
\(T\) 中的 \(A\) 值为 \(1\),\(\#\) 值为 \(0\);
-
\(C(x,y)=xy\).
对于每个字符只需要一次 FFT 就可以了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
typedef long long ll;
typedef double ld;
inline int Max(int x, int y) { return x > y ? x : y; }
inline int Min(int x, int y) { return x < y ? x : y; }
const int N = 800010;
const ld pi = acos(-1.0);
struct cpx {
ld x, y;
cpx(ld xx = 0, ld yy = 0) { x = xx; y = yy; }
};
cpx operator + (cpx a, cpx b) { return cpx(a.x + b.x, a.y + b.y); }
cpx operator - (cpx a, cpx b) { return cpx(a.x - b.x, a.y - b.y); }
cpx operator * (cpx a, cpx b) { return cpx(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
cpx *getw(int n, int type) {
static cpx w[N/2];
w[0] = cpx(1, 0); w[1] = cpx(cos(2 * pi / n), sin(2 * pi / n) * type);
for(int i = 2; i < n/2; ++i) w[i] = w[i-1] * w[1];
return w;
}
int p[N];
void FFT(cpx *a, int n, int type) {
for(int i = 0; i < n; ++i) if(i < p[i]) std::swap(a[i], a[p[i]]);
for(int i = 1; i < n; i <<= 1) {
cpx *w = getw(i << 1, type);
for(int j = 0; j < n; j += i << 1) {
cpx *b = a + j, *c = b + i;
for(int k = 0; k < i; ++k) {
cpx v = w[k] * c[k];
c[k] = b[k] - v;
b[k] = b[k] + v;
}
}
}
if(type == -1) for(int i = 0; i < n; ++i) a[i].x /= n;
}
void mul(int *a, int *b, int *c, int n, int m) {
static cpx f[N], g[N];
int len = 1, ct = 0;
while(len <= n + m) len <<= 1, ++ct;
for(int i = 0; i < len; ++i) p[i] = (p[i>>1]>>1) | ((i&1) << (ct-1));
for(int i = 0; i < len; ++i) f[i] = g[i] = cpx(0, 0);
for(int i = 0; i < n; ++i) f[i] = cpx(a[i], 0);
for(int i = 0; i < m; ++i) g[i] = cpx(b[i], 0);
FFT(f, len, 1);
FFT(g, len, 1);
for(int i = 0; i < len; ++i) f[i] = f[i] * g[i];
FFT(f, len, -1);
for(int i = 0; i < len; ++i) c[i] = (int)(f[i].x+0.5);
}
int n, m, k;
int id[300], c[4][N], A[4][N];
char s[N], t[N];
int f[N], g[N];
signed main() {
scanf("%d%d%d", &n, &m, &k);
id['A'] = 0, id['G'] = 1, id['C'] = 2, id['T'] = 3;
scanf("%s", s); scanf("%s", t);
for(int i = 0; i < n; ++i) {
s[i] = id[(int)s[i]]; t[i] = id[(int)t[i]];
++c[(int)s[i]][Max(i-k, 0)];
--c[(int)s[i]][Min(i+k+1, n)];
}
for(int i = 1; i < n; ++i) for(int j = 0; j < 4; ++j) c[j][i] += c[j][i-1];
for(int o = 0; o < 4; ++o) {
for(int i = 0; i < n; ++i)
f[i] = c[o][i] ? 0 : 1;
for(int i = 0; i < m; ++i)
g[i] = t[i] == o ? 1 : 0;
std::reverse(g, g + m);
mul(f, g, A[o], n, m);
}
int ans = 0;
for(int i = m-1; i < n; ++i)
if(!A[0][i] && !A[1][i] && !A[2][i] && !A[3][i])
++ans;
printf("%d\n", ans);
return 0;
}