[SCOI2014]方伯伯的玉米田题解

[SCOI2014]方伯伯的玉米田

题目描述

方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。这排玉米一共有 \(N\) 株,它们的高度参差不齐。方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。方伯伯可以选择一个区间,把这个区间的玉米全部拔高 \(1\) 单位高度,他可以进行最多 \(K\) 次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。问能最多剩多少株玉米,来构成一排美丽的玉米。

输入格式

第一行包含两个整数 \(n, K\),分别表示这排玉米的数目以及最多可进行多少次操作。第二行包含 \(n\) 个整数,第 \(i\) 个数表示这排玉米,从左到右第 \(i\) 株玉米的高度 \(a_i\)

输出格式

输出一个整数,最多剩下的玉米数。

样例 #1

样例输入 #1

3 1
2 1 3

样例输出 #1

3

提示

\(100\%\) 的数据满足:$2 \le N \lt 10^4 $,\(2 \le K \le 500\)\(1 \leq a_i \leq 5000\)

思路

定义 \(dp[i][j]\) 表示以 \(i\) 结尾,可以拔高 \(j\) 次的最长不下降子序列。

状态转移方程:

\[dp[i][j]=\max_{p,q}^{1 \le p < i,0\le q\le j,a[i]+j\ge a[p]+q} dp[p][q]+1 \]

直接暴力转移显然不行,时间复杂度 \(O(n^2k^2)\) ,一分没有。

观察发现每次拔高后最长不下降子序列的长度不会减少,所以可以用二维树状数组维护 \(dp\) 数组,但需要改一下状态。

\(dp[a][b]\) 表示 \([1,i-1]\) 中最多拔高 \(b\) 次,末尾不超过 \(a\) 的最长不下降子序列的长度(类似于 \(n\log n\) 求LIS的 \(low\) 数组)。

\(dp\) 数组丢到树状数组里就好了。

时间复杂度 \(O(nk\log n \log k)\)

代码

#include<bits/stdc++.h>
using namespace std;
int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
void write(int x){
	if(x<0){putchar('-');x=-x;}
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
int a[10005],f[10005][1005],n,k,maxx,_ans;
//树状数组模板
int lowbit(int x){
	return x&(-x);
}
void change(int x,int y,int val){
	for(int i=x;i<=maxx+k;i+=lowbit(i))
		for(int j=y;j<=k+1;j+=lowbit(j))
			f[i][j]=max(f[i][j],val);
}
int ask(int x,int y){
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
		for(int j=y;j;j-=lowbit(j))
			ans=max(ans,f[i][j]);
	return ans;
}
//---------------
int main(){
	n=read(),k=read();
	for(int i=1;i<=n;i++)a[i]=read(),maxx=max(maxx,a[i]);
	for(int i=1;i<=n;i++){
		for(int j=k;j>=0;j--){
			int t=ask(a[i]+j,j+1)+1;//找到dp[a[i]+j][j+1]
			_ans=max(_ans,t);//更新答案
			change(a[i]+j,j+1,t);//放入树状数组
		}
	}
	printf("%d\n",_ans);
	return 0;
}
posted @ 2022-12-03 17:45  maniubi  阅读(46)  评论(0编辑  收藏  举报