题解:P8776 [蓝桥杯 2022 省 A] 最长不下降子序列
P8776 最长不下降子序列
本题的非树状数组或线段树做法:
首先回顾一下 LIS 问题,也就是最长(严格)上升子序列,除了朴素的
然后来看本题。如果目前已经处理到了
那么这个问题可以简化为:
- 对于
j 位置元素a_j ,以a_j 结尾的在下标[0,j-k-1] 上的最长不下降子序列长度len_1 。 -
-
- 通过枚举
a_j ,得到len_1+len_2+len_3 即为该位置能得到的最长不下降子序列。
其中
int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int n, k;
cin >> n >> k;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
std::vector<int> r(n);
[&]() -> void {
std::vector<int> ends;
for (int i = n - 1; i >= 0; i--) {
int le = 0, ri = ends.size();
while (le < ri) {
int m = (le + ri) / 2;
if (ends[m] >= a[i]) {
le = m + 1;
} else {
ri = m;
}
}
r[i] = le + 1;
if (le == ends.size()) {
ends.push_back(a[i]);
} else {
ends[le] = a[i];
}
}
}();
r.push_back(0);
n++;
a.push_back(INF);
int ans = k;
[&]() -> void {
std::vector<int> ends;
for (int i = k; i < n; i++) {
int idx = std::upper_bound(ends.begin(), ends.end(), a[i - k]) - ends.begin();
if (idx == ends.size()) {
ends.push_back(a[i - k]);
} else {
ends[idx] = a[i - k];
}
idx = std::upper_bound(ends.begin(), ends.end(), a[i]) - ends.begin();
ans = std::max(ans, i != n - 1 ? k + idx + r[i] : k + idx + r[i] - 1);
}
}();
cout << ans << "\n";
return 0;
}