P3763 [TJOI2017] DNA 题解

这不看完就会做吗。

显然对于 SS 每个长度为 TT 判断即可,由于只改 33 个字符,所以我们求 LCP,然后 LCP 的下一个进行更改,最多 33 次就退出。

可以使用字符串哈希,不过我写的是后缀数组。复杂度瓶颈在于后缀排序和区间 RMQ,使用 DC3 或 SA-IS,且使用线性 RMQ 可以做到线性复杂度。不过我还是选择了好写的倍增。注意多测清空。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;

const int N = 2e5 + 5;

int t;
string S, T, p;
int n, m, x[N], y[N], sa[N], rk[N], height[N], c[N];

int tmp[N];

void suffix_array()
{
	m = 255;
	for (int i = 1; i <= m; i++) c[i] = 0;
	for (int i = 1; i <= n; i++) c[x[i] = p[i]]++;
	for (int i = 1; i <= m; i++) c[i] += c[i - 1];
	for (int i = n; i >= 1; i--) sa[c[x[i]]--] = i;
	for (int k = 1; k <= n; k <<= 1)
	{
		int idx = 0;
		for (int i = 1; i <= m; i++) c[i] = 0;
		for (int i = n - k + 1; i <= n; i++) y[++idx] = i;
		for (int i = 1; i <= n; i++)
		{
			if (sa[i] > k) y[++idx] = sa[i] - k;
		}
		for (int i = 1; i <= n; i++) c[x[i]]++, tmp[i] = x[y[i]];
		for (int i = 1; i <= m; i++) c[i] += c[i - 1];
		for (int i = n; i >= 1; i--)
		{
			sa[c[tmp[i]]--] = y[i], y[i] = 0;
		}
		swap(x, y);
		x[sa[1]] = 1, idx = 1;
		for (int i = 2; i <= n; i++)
		{
			if (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = idx;
			else x[sa[i]] = ++idx;
		}
		if (idx == n) break;
		m = idx;
	}
}

void get_height()
{
	for (int i = 1; i <= n; i++) rk[sa[i]] = i;
	int k = 0;
	for (int i = 1; i <= n; i++)
	{
		if (rk[i] == 1) continue;
		if (k) k--;
		while (i + k <= n && p[i + k] == p[sa[rk[i] - 1] + k]) k++;
		height[rk[i]] = k;
	}
}

int f[N][21], LG2[N];

void Init_LG2()
{
	for (int i = 2; i < N; i++) LG2[i] = LG2[i >> 1] + 1;
}

void Init_ST()
{
	for (int i = 1; i <= n; i++)
	{
		for (int j = 0; j < 21; j++) f[i][j] = 2e9;
	}
	for (int i = 1; i <= n; i++) f[i][0] = height[i];
	for (int j = 1; j <= LG2[n]; j++)
	{
		for (int i = 1; (i + (1 << j) - 1) <= n; i++)
		{
			f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
		}
	}
}

int query(int l, int r)
{
	int g = LG2[r - l + 1];
	return min(f[l][g], f[r - (1 << g) + 1][g]);
}

int querylcp(int x, int y)
{
	int l = rk[x], r = rk[y];
	if (l > r) swap(l, r);
	return query(l + 1, r);
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	Init_LG2();
	cin >> t;
	while (t--)
	{
		cin >> S >> T;
		if (T.size() > S.size())
		{
		    cout << "0\n";
		    continue;
		}
		p = S + "Z" + T;
		n = p.size();
		p = " " + p;
		for (int i = 1; i <= n; i++)
		{
			sa[i] = x[i] = y[i] = rk[i] = height[i] = tmp[i] = 0;
		}
		suffix_array();
		get_height();
		Init_ST();
		int ans = 0;
		for (int i = 0; i + T.size() - 1 < S.size(); i++)
		{
			int nowl = i + 1, nowr = S.size() + 2;
			int cnt = 0;
			while (nowr <= n)
			{
				int len = querylcp(nowl, nowr);
				nowl += len, nowr += len;
				if (nowr > n)
				{
					ans++;
					goto E;
				}
				if (cnt == 3) break;
				cnt++;
				nowl++, nowr++;
			}
			if (nowr > n) ans++;
		E:;
		}
		cout << ans << "\n";
	}
	return 0;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示