P3763 [TJOI2017] DNA 题解
这不看完就会做吗。
显然对于
可以使用字符串哈希,不过我写的是后缀数组。复杂度瓶颈在于后缀排序和区间 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;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现