L. Longest Array Deconstruction

L. Longest Array Deconstruction

https://codeforces.com/contest/1575/problem/L

题目大意

给出一组数\(a\),你可以删除任意数,要求在任意次操作后的数组中满足\(a[i] == i\)的数量最大。

解题思路

考虑\(dp\),首先枚举删除的数量,即数的移动次数,对于第\(i\)个数,如果\(a[i] > i\)则此数无法对答案造成贡献,因为\(i\)只能减少,所以无法得到\(a[i] = i\),故初始时只需要\(i >= a[i]\)的情况即可。

很显然的转移方程是移动次数多的状态可以由移动次数少的状态转移,所以从小到大枚举每个位置的移动次数,对于第\(i\)个位置的值\(a_i\),答案即是\(dp[a_i] = max_{1 \leq j \leq {a_i-1}}dp[j] + 1\)\(dp[i]\)表示以\(i\)结尾的答案。所以\(dp[n]\)即使最终结果。

这里可以使用树状数组维护和更新最大值来求\(dp\)值。

Code

#include <bits/stdc++.h>
#define lowbit(x) x&-x
const int  N = 2e5+7;

using namespace std;

int a[N];
set<int>v[N];
int tree[N];
void add(int i,int y){
	while(i < N){
		tree[i] = max(tree[i], y);
		i += lowbit(i);
	}
}


int getsum(int i)
{
	int res = 0;
	while(i > 0){
		res = max(res, tree[i]);
		i -= lowbit(i);
	}
	return res;
}

void solve()
{
	int n;
	scanf("%d",&n);
	for(int i = 1; i <= n;i++){
		scanf("%d",&a[i]);
		if(i - a[i] >= 0)
			v[i - a[i]].insert(a[i]);
	}
	int ans = 0;
	for(int i = 0; i < N; i++){
		for(int j : v[i]){
			ans = (getsum(j-1));
			add(j, ans + 1);
		}
	}
	printf("%d\n",getsum(n));

}

int  main()
{
	solve();	
	return 0;
}
posted @ 2021-11-09 16:46  !^^!  阅读(144)  评论(0编辑  收藏  举报