CF946G
首先将所有 \(a_i\gets a_i-i\)。
设 \(f_{i,0/1}\) 表示前 \(i\) 个数字,强制选第 \(i\) 个数,未删过数字/已经删过数字的最长不下降子序列的长度。
则有 \(f_{i,0}=\max\limits_{a_j\le a_i}\left\{f_{j,0}\right\}+1\),\(f_{i,1}=\max\limits_{a_j\le a_i}\left\{f_{j,1}\right\}+1\).
对于去掉一个元素的情况,发现后面所有点的下标都会减去 \(1\),因此 \(f_{i,1}=\max\limits_{a_j\le a_i+1,j\lt i-1}\left\{f_{j,0}\right\}+1\)。
将所有涉及到的值离散化后用树状数组维护即可。
具体细节看代码。
Code:
#include <bits/stdc++.h>
using namespace std;
const int N = 200005, M = 400005;
int n;
int a[N], b[N], _[M], tot;
int c[M][3];
int f[N][2];
void upd(int x, int y, int k) { for (; x <= tot; x += x & -x) c[x][k] = max(c[x][k], y); }
int query(int x, int k) { int res = 0; for (; x; x -= x & -x) res = max(res, c[x][k]); return res; }
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), a[i] -= i, b[i] = a[i] + 1, _[++tot] = a[i], _[++tot] = b[i];
sort(_ + 1, _ + tot + 1), tot = unique(_ + 1, _ + tot + 1) - (_ + 1);
for (int i = 1; i <= n; ++i) a[i] = lower_bound(_ + 1, _ + tot + 1, a[i]) - _, b[i] = lower_bound(_ + 1, _ + tot + 1, b[i]) - _;
int ans = 0;
for (int i = 1; i <= n; ++i) {
int val1 = query(a[i], 0), val2 = query(a[i], 1), val3 = query(b[i], 2);
f[i][0] = val1 + 1, f[i][1] = val2 + 1; if (i > 2) f[i][1] = max(f[i][1], val3 + 1);
upd(a[i], f[i][0], 0), upd(a[i], f[i][1], 1); if (i > 1) upd(a[i - 1], f[i - 1][0], 2);
ans = max(ans, max(f[i][0], f[i][1]));
}
printf("%d", max(0, n - 1 - ans));
return 0;
}