标签:names ems soft height mic its out 二分 描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。
小Hi在练习过很多曲子以后发现很多作品自身包含一样的旋律。旋律是一段连续的数列,相似的旋律在原数列可重叠。比如在1 2 3 2 3 2 1 中 2 3 2 出现了两次。
小Hi想知道一段旋律中出现次数至少为K次的旋律最长是多少?
第一行两个整数 N和K。1≤N≤20000 1≤K≤N
接下来有 N 个整数,表示每个音的数字。1≤数字≤100
一行一个整数,表示答案。
Sample Input
8 2
1
2
3
2
3
2
3
1
Sample Output
4
总结:打算把后缀数组复习一遍
本题很明显求的是连续k个height数组的最小值当中的最大值,
然后有两种做法二分或单调队列
这里用的是单调队列
#include <bits/stdc++.h> using namespace std; const int maxn = 200005; int n, K, rk[maxn], sa[maxn], y[maxn], ln, p, m, c[maxn]; int H[maxn], wr[maxn], q[maxn], l, r, a[maxn], pos[maxn], k; bool cmp(int k1, int k2, int ls) { return wr[k1] == wr[k2] && wr[k1 + ls] == wr[k2 + ls]; } void SA(int x) { m = x; for (int i = 1; i <= n; ++i) c[rk[i]]++; for (int i = 1; i <= m; ++i) c[i] += c[i - 1]; for (int i = n; i >= 1; --i) sa[c[rk[i]]--] = i; ln = 1, p = 0; while(p < n) { k = 0; for (int i = n - ln + 1; i <= n; ++i) y[++k] = i; for (int i = 1; i <= n; ++i) if(sa[i] > ln) y[++k] = sa[i] - ln; memset(c, 0, sizeof c); for (int i = 1; i <= n; ++i) wr[i] = rk[i]; for (int i = 1; i <= n; ++i) c[wr[y[i]]]++; for (int i = 1; i <= m; ++i) c[i] += c[i - 1]; for (int i = n; i >= 1; --i) sa[c[wr[y[i]]]--] = y[i]; for (int i = 1; i <= n; ++i) wr[i] = rk[i]; rk[sa[1]] = 1; p = 1; for (int i = 2; i <= n; ++i) { if(!cmp(sa[i], sa[i - 1], ln)) ++p; rk[sa[i]] = p; } } ln <<= 1; m = p; } void Gh() { k = 0; for (int i = 1; i <= n; ++i) rk[sa[i]] = i; for (int i = 1; i <= n; ++i) { if(k) --k; int j = sa[rk[i] - 1]; while(a[i + k] == a[j + k]) ++k; H[rk[i]] = k; } } int main() { scanf("%d%d", &n, &K); for (int i = 1; i <= n; ++i) scanf("%d", &rk[i]), a[i] = rk[i]; SA(105); Gh(); int ans = 0; for (int i = 1; i <= n; ++i) { while(l < r && H[i] < q[r]) r--; q[++r] = H[i]; pos[r] = i; while(l < r && pos[l] <= i - K + 1) ++l; if(i >= K) ans = max(ans, q[l]); } printf("%d\n", ans); for (int i = 1; i <= n; ++i) cout << H[i] << " "; return 0; }
标签:names ems soft height mic its out 二分 描述
原文地址:https://www.cnblogs.com/oi-forever/p/9153095.html