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();
}