方伯伯的玉米田

方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。这排玉米一共有 \(N\) 株,它们的高度参差不齐。

方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。方伯伯可以选择一个区间,把这个区间的玉米全部拔高 \(1\) 单位高度,他可以进行最多 \(K\) 次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。

问能最多剩多少株玉米,来构成一排美丽的玉米。

对于所有数据,\(1 < N < 10000,\ 1 < K \leq 500,\ 1 \leq a_i \leq 5000\)

题解

javascript:void(0)
javascript:void(0)

首先,通过思考我们可以得出每次操作区间的右端点一定为\(n\),否则后面玉米的高度相对前面的高度就会减少,被拔的也就会变多,不满足最优。

由此,我们可以设\(f(i,j)\)表示以第\(i\)个玉米为结尾,且第\(i\)个玉米被拔高了\(j\)次的最长非降子序列长度。

\[f(i,j)=\max_{x< i,y\leq j}\{f(x,y)+1\mid a_x+y\leq a_i+j\} \]

考虑用数据结构维护这个转移。\(x< i\)显然不用管,\(a_x+y\leq a_i+j\)\(y\leq j\)可以用二维树状数组维护。具体而言,我们可以把\(f(x,y)\)存到二维树状数组里的\(g(a_x+y,y)\),然后对\(f(i,j)\)查询\(g(a_i+j,j)\)就行了。

时间复杂度\(O(nK\log(a_iK))\)

int n,K,mx;
int a[10010],s[5510][510];

#define lowbit(x) (x&-x)
void insert(int x,int y,int v){
	for(int i=x;i<=mx+K;i+=lowbit(i))
		for(int j=y+1;j<=K+1;j+=lowbit(j))
			s[i][j]=max(s[i][j],v);
}
int query(int x,int y){
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
		for(int j=y+1;j;j-=lowbit(j))
			ans=max(ans,s[i][j]);
	return ans;
}
#undef lowbit

int main(){
	read(n),read(K);
	for(int i=1;i<=n;++i) read(a[i]);
	mx=*max_element(a+1,a+n+1);
	for(int i=1;i<=n;++i)for(int j=K;j>=0;--j)
		insert(a[i]+j,j,query(a[i]+j,j)+1);
	printf("%d\n",query(mx+K,K));
	return 0;
}