「题解」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;
}
上一篇:高精度LD温控板 半导体激光器激光二极管的精确控温及倍频晶体的温控


下一篇:Java--事务及使用