洛谷 P3287 [SCOI2014] 方伯伯的玉米田 题解

题目传送门

题目大意

给定一个长度为 N 的序列 a,可以进行最多 K 次操作,每次操作可以选择一个区间加 1
求操作之后最长的最长不降升子序列长度。
1N1041K5001ai5000

题目解析

要让最长不降升子序列最长,那么显然要让后面的数更大,所以每次操作的右端点选择 N 肯定不劣。
f(i,j) 为前 i 个 LIS 为 i,使用了 k 次操作的最长 LIS 长度。
假设从 k 转移,如果 akai,直接转移,否则使用操作把 ai 变成和 ak 一样大即可。

f(i,j)=max1k<i{f(k,j)+1akaif(k,j+aiak)+1ak>ai

朴素刷表转移为 O(N2K)

考虑优化。
第一种转移,转移前后的 j 相同,每次从更小或者相同的 ai 转移,对于每个 j 维护 low(j,V)=maxaiVf(i,j)
第二种转移,转移前后的 ai+j 相同,每次从更小或者相同的 j 转移,对于每个 a[i]+j 维护 over(A,B)=maxai+j=A,jBf(i,j)
开若干个树状数组维护前缀最大值即可。
时间复杂度 O(nklogai)

#define maxn 10039
int n,m,k,a[maxn],f[maxn][539],ans;
class BIT{
public:
#define lowbit(x) (x&-x)
int c[5539];
int query(int x){ int s=-1; while(x) s=mmax(s,c[x]),x-=lowbit(x); return s; }
void add(int x,int y){ while(x<=m) c[x]=mmax(c[x],y),x+=lowbit(x); return; }
}lo[539],ov[5539],sum;
int main(){
fin>>n>>k; int i,j; for(i=1;i<=n;i++) fin>>a[i],m=mmax(a[i],m);
for(i=1;i<=n;i++) for(j=0;j<=k;j++){
f[i][j]=mmax(lo[j].query(a[i]),ov[a[i]+j].query(j+1))+1;
ans=mmax(ans,f[i][j]);
lo[j].add(a[i],f[i][j]);
ov[a[i]+j].add(j+1,f[i][j]);
}
fin<<ans<<'\n';
return 0;
}
posted @   jiangtaizhe001  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2022-10-27 CSP 2022 S2 游记
2021-10-27 CSP2021S2T1 廊桥分配 题解
2021-10-27 关于 C++ STL 的用法(部分,自行备忘)
点击右上角即可分享
微信分享提示