K 题
题解
在数组 中,每个给出的
前一定有一段
的子序列,不妨把这段子序列连续地放在
前,之后判断构造出的数组
是否合法。
数组 合法即
且不存在两个相邻的数后者与前者之差大于
。
之后,考虑 的位置,因为
是最小的,每次出现一定会将栈清空且无法被之后的数清空,所以
一定在最右的
处。
接下来考虑 的位置,因为此时
是剩下未使用过的数中最小的数,所以
会在次右的
或最右的
处。
……
重复以上步骤直至将 个数放完。
即,将构造好的数组 按值从小到大,位置从右至左的顺序依次赋上
即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<int> b(n);
vector<bool> vis(n);
for (int i = 0; i < k; i++) {
int p, x;
cin >> p >> x;
--p;
b[p] = x;
vis[p] = true;
}
for (int i = 0; i < n; i++) {
if (vis[i]) { // 如果是给出的 b[i]
for (int j = i - 1; j >= 0 and not vis[j]; j--) { // 将 1,2,...,b[i] - 1 连续地放在 b[i] 前
b[j] = max(1, b[j + 1] - 1);
}
}
}
for (int i = 1; i < n; i++) { // 防止没给出 b[n - 1],因为之前只往左放
if (b[i] == 0) {
b[i] = b[i - 1];
}
}
bool ok = b[0] == 1;
for (int i = 1; i < n; i++) { // 判断构造出的数组 b 是否合法
if (b[i] - b[i - 1] > 1) {
ok = false;
}
}
if (not ok) {
cout << -1 << "\n";
return 0;
}
vector<int> p(n);
iota(p.begin(), p.end(), 0);
sort(p.begin(), p.end(), [&](int x, int y) { // 按值从小到大,位置从右至左的顺序排序
return b[x] != b[y] ? b[x] < b[y] : x > y;
});
vector<int> ans(n);
for (int i = 0; i < n; i++) { // 依次赋上 1,2,...,n
ans[p[i]] = i + 1;
}
for (int i = 0; i < n; i++) {
cout << ans[i] << " \n"[i == n - 1];
}
return 0;
} 
京公网安备 11010502036488号