解题思路
看题解区的大佬们用的都是单调栈,本蒟蒻献上一篇线段树题解。
整个数最大,首先位数是确定的,则肯定优先考虑高位大小。
大体思路就是从前向后依次求出每一位的值(好像是废话)。
-
对于第 i i i 位,首先确定这个数在字符串中的位置哪个区间里。
对于左边界,在上一个数后面(第一个数就是 1 1 1);对于右边界,右边肯定要有 n − k − i n-k-i n−k−i 个数,最大是 k + i + 1 k+i+1 k+i+1。 -
然后我们就是求出这个区间中的最大值,当然下标也要确定。这一点就可以用线段树模板预处理,方法略。
-
接着就是每次更新区间边界,然后 l o g n logn logn 查询,总时间复杂度为 O ( k l o g n ) O(klogn) O(klogn)。
代码实现
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n, k;
string a;
struct Sec {
int maxv, idx;
} sec[N << 2];
inline Sec Max(Sec x, Sec y) {
if (x.maxv != y.maxv) {
return x.maxv > y.maxv ? x : y;
}
return x.idx < y.idx ? x : y;
}
inline void pushup(int id) {
sec[id] = Max(sec[id << 1], sec[id << 1 | 1]);
}
void build(int id, int l, int r) {
if (l == r) {
sec[id] = {a[l], l};
return;
}
int mid = l + r >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
Sec query(int id, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return sec[id];
}
int mid = l + r >> 1;
Sec res = {-1, 0};
if (x <= mid) {
res = Max(res, query(id << 1, l, mid, x, y));
}
if (y > mid) {
res = Max(res, query(id << 1 | 1, mid + 1, r, x, y));
}
return res;
}
string res;
int main() {
ios :: sync_with_stdio(0);
cin >> n >> k >> a;
a = " " + a;
for (int i = 1; i <= n; ++i) {
a[i] ^= '0';
}
build(1, 1, n);
int l = 1, r = k + 1;
for (int i = 1; i <= n - k; ++i) {
Sec s = query(1, 1, n, l, r);
res += to_string(s.maxv);
l = s.idx + 1;
++r;
}
cout << res << '\n';
return 0;
}
Good Good 贺题,Day Day Up!!