题目链接:https://codeforces.com/contest/1437/problem/E
题意
给出一个大小为 (n) 的数组 (a) 和一个下标数组 (b),每次操作可以选择数组 (b) 外的任意下标 (i) 并将 (a_i) 赋值为任意数,问能否经过操作使得数组 (a) 严格递增,如果可以,计算所需的最少操作次数。
题解
令 (c_i = a_i - i),如果数组 (a) 严格递增,那么数组 (c) 一定为非递减序。
所以判断下标数组 (b) 对应的数组 (c) 是否为非递减序,如果是,则有解,选取数组 (b) 中两两相邻的数为左右端点,并在数组 (c) 内寻找该区间内的最长非下降子序列,其余数则均需要改变。
Tips
数组 (b) 可能不包含首尾下标,所以需要在 (b) 首尾再添加两个下标使得两两形成的区间可以取到所有数。
代码
#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> c(n + 2);
c[0] = -2e9;
for (int i = 1; i <= n; i++) cin >> c[i], c[i] -= i;
c[n + 1] = 2e9;
vector<int> b(k + 2);
b[0] = 0;
for (int i = 1; i <= k; i++) cin >> b[i];
b[k + 1] = n + 1;
int ans = 0;
for (int i = 0; i < k + 1; i++) {
int l = b[i], r = b[i + 1];
if (c[l] > c[r]) {
cout << -1 << "
";
return 0;
}
vector<int> lis;
for (int j = l + 1; j < r; j++) {
if (c[l] <= c[j] and c[j] <= c[r]) {
auto it = upper_bound(lis.begin(), lis.end(), c[j]);
if (it == lis.end()) lis.push_back(c[j]);
else *it = c[j];
}
}
ans += (r - l - 1) - lis.size();
}
cout << ans << "
";
return 0;
}