1 条题解
-
0
出现至少 𝑘 次意味着后缀排序后有至少连续 𝑘 个后缀以这个子串作为公共前缀.
所以,求出每相邻 𝑘 −1 个 ℎ𝑒𝑖𝑔ℎ𝑡 的最小值,再求这些最小值的最大值就是答案.
可以使用单调队列 𝑂(𝑛) 解决,但使用其它方式也足以 AC.
#include <cstring> #include <iostream> #include <set> using namespace std; constexpr int N = 40010; int n, k, a[N], sa[N], rk[N], oldrk[N], id[N], px[N], cnt[1000010], ht[N], ans; multiset<int> t; // multiset 是最好写的实现方式 bool cmp(int x, int y, int w) { return oldrk[x] == oldrk[y] && oldrk[x + w] == oldrk[y + w]; } int main() { cin.tie(nullptr)->sync_with_stdio(false); int i, j, w, p, m = 1000000; cin >> n >> k; --k; for (i = 1; i <= n; ++i) cin >> a[i]; // 求后缀数组 for (i = 1; i <= n; ++i) ++cnt[rk[i] = a[i]]; for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; for (i = n; i >= 1; --i) sa[cnt[rk[i]]--] = i; for (w = 1; w < n; w <<= 1, m = p) { for (p = 0, i = n; i > n - w; --i) id[++p] = i; for (i = 1; i <= n; ++i) if (sa[i] > w) id[++p] = sa[i] - w; memset(cnt, 0, sizeof(cnt)); for (i = 1; i <= n; ++i) ++cnt[px[i] = rk[id[i]]]; for (i = 1; i <= m; ++i) cnt[i] += cnt[i - 1]; for (i = n; i >= 1; --i) sa[cnt[px[i]]--] = id[i]; memcpy(oldrk, rk, sizeof(rk)); for (p = 0, i = 1; i <= n; ++i) rk[sa[i]] = cmp(sa[i], sa[i - 1], w) ? p : ++p; } for (i = 1, j = 0; i <= n; ++i) { // 求 height if (j) --j; while (a[i + j] == a[sa[rk[i] - 1] + j]) ++j; ht[rk[i]] = j; } for (i = 1; i <= n; ++i) { // 求所有最小值的最大值 t.insert(ht[i]); if (i > k) t.erase(t.find(ht[i - k])); ans = max(ans, *t.begin()); } cout << ans; return 0; }
- 1
信息
- ID
- 1917
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 2
- 上传者