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 - ans - 1);
	return 0;
}
原文地址:https://www.cnblogs.com/cxhscst2/p/8663244.html