Description
给你一个长度为 \(n\) 的序列 \(A\) 。现在准许你删除任意一个数,删除之后需要修改最小的次数使序列单调递增。问最小次数。
\(1\leq n\leq 200000\)
Solution
注意到如果不要删除一个数的话,显然这就是一个模型问题了。只需要求出序列中每个数减去其位权,求出最长单调不下降子序列长度 \(len\) 。答案就是 \(n-len\) 。
但要删除一个数的话就不好直接做了,考虑问题出在了哪里。
因为删除一个数后,这个数之后的所有位权都 \(-1\) 。即实际上是对于删除的这个数,相当于断点,断点前每个数减去位权,断点后每个数减去(位权 \(-1\) )。再用相同的方法处理。
令 \(f_{i,1/0}\) 表示第 \(i\) 位及以前是否进行过“删数”操作,得到的最长不降序列长度。依旧可以用二分优化。
Code
//It is made by Awson on 2018.3.12#include#define LL long long#define dob complex #define Abs(a) ((a) < 0 ? (-(a)) : (a))#define Max(a, b) ((a) > (b) ? (a) : (b))#define Min(a, b) ((a) < (b) ? (a) : (b))#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))#define writeln(x) (write(x), putchar('\n'))#define lowbit(x) ((x)&(-(x)))using namespace std;const int N = 200000, INF = ~0u>>1;void read(int &x) { char ch; bool flag = 0; for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar()); for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar()); x *= 1-2*flag;}void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }int n, f[N+5], g[N+5], ans, t, a[N+5];void work() { read(n); for (int i = 1; i <= n; i++) read(a[i]), f[i] = g[i] = INF; f[0] = g[0] = -INF; for (int i = 2; i <= n; i++) { t = upper_bound(f+1, f+n+1, a[i]-i+1)-f; ans = Max(ans, t); f[t] = a[i]-i+1; t = upper_bound(g+1, g+n+1, a[i-1]-i+1)-g; ans = Max(ans, t); g[t] = a[i-1]-i+1, f[t] = Min(f[t], g[t]); } writeln(n-1-ans);}int main() { work(); return 0;}