LGP3287题解

首先考虑区间加对应什么东西。

对应的显然是差分序列上某个位置 \(+1\) 某个位置 \(-1\)

再考虑单调不降意味着什么。

对应的是划分成若干个区间,每个区间的和不小于 \(0\)

所以就有一个结论,区间加一定不优于后缀加。

不过其实注意到一点,你并不关心你是哪个位置的数,你只关心你有多大。

所以设 \(dp[i][k]\) 当前序列最后一个元素为 \(i\),且进行了 \(k\) 次修改的最大长度。

考虑增加一个元素时如何转移到 \(dp[i][k]\),容易发现有 \(dp[i][k]=\max(dp[i][k],1+\max(\max_{j=1}^{i}dp[j][k],\max_{j=i}^{n}dp[j][k-(j-i)]))\)

这是一个在 dp 数组上斜着的东西和一个在 dp 数组上面横着的东西,维护前缀最大值和后缀最大值即可,使用树状数组。

显然有单调性 \(dp[i][k]\leq dp[i][k+1]\)

复杂度 \(O(nk\log n)\),应该可以通过吧。

#include<cstdio>
#include<cctype>
namespace SOLVE{
	const int M=5005;
	int n,m,k,a[M*2],dp[M][505];
	inline int max(const int&a,const int&b){
		return a>b?a:b;
	}
	struct BIT{
		int mx[M];
		inline void Ins(int x,const int&w){
			while(x<=m)mx[x]=max(mx[x],w),x+=x&-x;
		}
		inline int Qry(int x){
			int ans(0);while(x>=1)ans=max(ans,mx[x]),x-=x&-x;return ans;
		}
	}fx[505],fy[M+505];
	inline int read(){
		int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
	}
	inline void Ins(const int&V,const int&K,const int&w){
		if(w<dp[V][K])return;dp[V][K]=max(dp[V][K],w);
		fx[K].Ins(V,dp[V][K]);fy[V+K].Ins(m+1-V,dp[V][K]);
	}
	inline int Qry(const int&V,const int&K){
		return max(fx[K].Qry(V),fy[V+K].Qry(m+1-V));
	}
	inline void main(){
		int ans(0);n=read();k=read();for(int i=1;i<=n;++i)if((a[i]=read())>m)m=a[i];
		for(int i=1;i<=n;++i)for(int mx(0),j=0;j<=k;++j)Ins(a[i],j,mx=max(mx,Qry(a[i],j)+1));
		for(int i=1;i<=m;++i)for(int j=0;j<=k;++j)ans=max(ans,dp[i][j]);printf("%d",ans);
	}
}
signed main(){
	SOLVE::main();
}
posted @ 2022-09-13 19:31  Prean  阅读(12)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};