Educational Codeforces Round 97 (Rated for Div. 2)

E. Make It Increasing Educational Codeforces Round 97 (Rated for Div. 2)

题目连接

题解:

因为b[i]的值是确定,所以知道操作 b[i] 到b[i - 1]的区间, 当 \(a[i] - a[j] < i - j (i > j)\) 那么可以证明一定无法构成, 所以先判断是否可以构造,如果都满足, 那么对与每段 \(b[i - 1]\)\(b[i]\) 可以先将\(a[i] = a[i] - i\)

这样做的目的是保证存在 \(a[i] > a[j] ,且 i > j\) 那么就是且以 \(b[i - 1]\)开始 \(b[i]\) 结束的最长上升子序列, 可以用二分优化到 n * log(n)也可以用线段树优化。

代码:

#include<bits/stdc++.h>
    using namespace std;
     
    const int N = 5e5 + 7;
    typedef long long ll;
     
    ll a[N], n, k, b[N];
    int rt;
     
    int tree[40 * N], ls[40 * N], rs[40 * N], dp[N];
    int top = 1;
    #define m (l + r) / 2
    void update(int v, int pos, int l, int r, int &node) {
        if (node == 0) node = top++;
        if (l == r) {
            tree[node] = v;
            return;
        }
        if (pos <= m) update(v, pos, l, m, ls[node]);
        else update(v, pos, m + 1, r, rs[node]);
        tree[node] = max(tree[ls[node]], tree[rs[node]]);
    }
     
    int query(int ql, int qr, int l, int r, int node) {
        if (ql <= l && qr >= r) {
            return tree[node];
        }
        int ans = 0;
        if (ql <= m) ans = max(ans, query(ql, qr, l, m, ls[node]));
        if (qr > m) ans = max(ans, query(ql, qr, m + 1, r, rs[node]));
        return ans;
    }
     
    int work(int l, int r) {
        int maxn = n + 2;
        for (int i = l; i <= r; i++) {
            dp[i] = 0;
        }
        for (int i = l + 1; i <= r; i++) {
            if (a[i] >= a[l]) {
                dp[i] = 2;
            } else {
                dp[i] = -1e8;
            }
        }
     
        for (int i = l + 1; i <= r; i++) {
            dp[i] = max(dp[i], query(1, a[i], 1, maxn, rt) + 1);
            if (dp[i] > 1)
            update(dp[i], a[i], 1, maxn, rt);
        }
     
        for (int i = l; i <= r; i++) {
            update(0, a[i], 1, maxn, rt);
        }
        
        if (dp[r] < 2) {
            return -1;
        }
        return (r - l + 1) - dp[r];
        
    }
     
    vector<int> g;
     
    int get_id(int x) {
        return lower_bound(g.begin(), g.end(), x) - g.begin() + 1;
    }
     
    int main() {
        ios::sync_with_stdio(0);
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            a[i] = a[i] - i;
            g.push_back(a[i]);
        }
        sort(g.begin(), g.end());
        g.erase(unique(g.begin(), g.end()), g.end());
        for (int i = 1; i <= k; i++) {
            cin >> b[i];
        }
     
        for (int i = 1; i <= n; i++) {
            a[i] = get_id(a[i]);
        }
        b[0] = 0;
        b[k + 1] = n + 1;
        a[0] = 0;
        a[n + 1] = n + 2;
     
        int ans = 0;
     
        for (int i = 1; i <= k + 1; i++) {
            int cnt = work(b[i - 1], b[i]);
            if (cnt < 0) {
                cout << -1 << endl;
                return 0;
            }
            ans += cnt;
        }
        cout << ans << endl;
     
     
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值