[Codeforces 946G]Almost Increasing Array

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 <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#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;
}
posted @ 2018-03-13 10:39  NaVi_Awson  阅读(353)  评论(0编辑  收藏  举报