洛谷P1776 宝物筛选_NOI导刊2010提高(02)(多重背包,单调队列)
为了学习单调队列优化DP奔向了此题。。。
基础的多重背包就不展开了。设为选前个物品,重量不超过的最大价值,为重量,为价值(蒟蒻有强迫症,特别不喜欢把和反着搞,和嘛!),直接给转移方程
显然,都是从转过来的,所以第一维可以滚掉,得到每次转移的更简化的方程
这样是的,还是要想办法优化。
众所周知,DP优化的根本原则是去掉无用的状态、利用重复转移的状态。可是这方程一眼根本看不出什么可优化的地方啊。。。。。。
我们要像这位Dalao一样善于发现,他的blog
所以,不管这个想法是怎么来的,我们先把按模意义下分组,设,那么一组里的都是同一个值。
然后方程就变成了这样
突然看到了的重复出现!这也就意味着,在每一组中,有意义的状态只有种!(是最大载重)每次总的状态也就只有了。
设。那么因为有的限制,所以对于每个,我们需要且只能从转移。对于这样的转移,可以形象地和滑动窗口联系一下,相当于有一个宽度为的窗口从一边一步步往另一边移动,每移一次都要取出窗口内的最大值。这个就上单调队列维护。
首先枚举。接着,为了方便滚动,我们从大到小枚举和,用一个单调队列维护下标在范围内的依次递减的若干个值,因为显然如果有的话是没有用的。枚举时,每次队首元素超出了范围就把它出队。用现在的队首更新即。接着下一个元素要入队了,把队尾比这个小的全出队,再让它进来。最后输出即可。
这样就是的了,比二进制拆分难理解些但是更优秀了。
结合代码理解会更轻松哦
#include<cstdio>
#define RG register
#define R RG int
#define G c=getchar()
const int N=1e5+9;
int f[N],g[N],q[N];
inline int in(){
RG char G;
while(c<'-')G;
R x=c&15;G;
while(c>'-')x=x*10+(c&15),G;
return x;
}
inline int max(R x,R y){return x>y?x:y;}
inline void chkmx(R&x,R y){if(x<y)x=y;}
int main(){
R n=in(),maxw=in(),maxk,lim,v,w,m,d,i,k,k1,h,t,now;
for(i=1;i<=n;++i){
v=in();w=in();m=in();
for(d=0;d<w;++d){//枚举余数
maxk=(maxw-d)/w;lim=max(maxk-m,0);//先确定最初的范围
for(t=0,k=maxk-1;k>=lim;--k){//窗口先扩大宽度到m
now=f[k*w+d]-k*v;
while(t&&g[t]<=now)--t;//维护单调性
g[++t]=now;q[t]=k;
}
for(h=1,k1=maxk;~k1;--k1,--k){//可以开始转移了
if(h<=t&&q[h]>=k1)++h;//接着移动
if(h<=t)chkmx(f[k1*w+d],g[h]+k1*v);//转移
if(k<0)continue;//注意窗口可能已经出正数范围了
now=f[k*w+d]-k*v;
while(h<=t&&g[t]<=now)--t;//维护单调性
g[++t]=now;q[t]=k;
}
}
}
printf("%d\n",f[maxw]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具