Codeforces 946G Almost Increasing Array (树状数组优化DP)
题目链接 Educational Codeforces Round 39 Problem G
题意 给定一个序列,求把他变成Almost Increasing Array需要改变的最小元素个数。
Almost Increasing Array为删掉至多一个元素之后可以成为严格递增子序列的数列。
这类题有个常见的套路,就是对每个元素减去下标之后求LIS。
这道题中可以删去一个元素,我们可以枚举哪个元素是被删掉的,
那么他之前的元素求LIS的时候真正的值为$a_{i} - i$,他之后的元素求LIS的时候真正的值为$a_{i} - i + 1$,
最后取LIS的最大值$ans$,答案即为$n - ans - 1$。
用树状数组优化DP即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 2e5 + 10; int a[N], b[N], c[N << 1], d[N], e[N << 1]; int s1[N], s2[N]; int cnt, tot; int n, mx, ans = 0; inline void up(int &a, int b){ if (a < b) a = b;} void update(int x, int val){ for (; x <= mx; x += x & -x) up(c[x], val); } int query(int x){ int ret = 0; for (; x; x -= x & -x) up(ret, c[x]); return ret;} int main(){ scanf("%d", &n); rep(i, 1, n) scanf("%d", a + i); rep(i, 1, n) b[i] = a[i] - i, d[i] = a[i] - i + 1; rep(i, 1, n) e[++tot] = b[i], e[++tot] = d[i]; sort(e + 1, e + n * 2 + 1); cnt = unique(e + 1, e + tot + 1) - e - 1; rep(i, 1, n) b[i] = lower_bound(e + 1, e + cnt + 1, b[i]) - e; rep(i, 1, n) d[i] = lower_bound(e + 1, e + cnt + 1, d[i]) - e; memset(c, 0, sizeof c); mx = 4e5; rep(i, 1, n){ s1[i] = query(b[i]) + 1; update(b[i], s1[i]); } memset(c, 0, sizeof c); rep(i, 1, n) d[i] = mx - d[i] + 1; dec(i, n, 1){ s2[i] = query(d[i]) + 1; update(d[i], s2[i]); } rep(i, 1, n) d[i] = mx - d[i] + 1; memset(c, 0, sizeof c); ans = s1[n - 1]; up(ans, s2[2]); rep(i, 2, n){ up(ans, query(d[i]) + s2[i]); update(b[i - 1], s1[i - 1]); } memset(c, 0, sizeof c); rep(i, 1, n) b[i] = mx - b[i] + 1, d[i] = mx - d[i] + 1; dec(i, n - 1, 1){ up(ans, query(b[i]) + s1[i]); update(d[i + 1], s2[i + 1]); } printf("%d\n", n - ans - 1); return 0; }