Educational Codeforces Round 97 (Rated for Div. 2) E. Make It Increasing(最长非下降子序列)

题目链接: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 << "\n";
            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 << "\n";

    return 0;
}
posted @ 2020-10-29 17:35  Kanoon  阅读(96)  评论(0编辑  收藏  举报