P3188 [HNOI2007] 梦幻岛宝珠-题解
20230918
P3188 [HNOI2007] 梦幻岛宝珠
Statement
01背包,
物体的体积可以写成
Solution
发现
那我们考虑对背包进行分组。
用
每一组就直接用普通背包做就可以了。
现在考虑如何合并?
从
我们考虑可以从
假设拿上来
其中
我就可以多拿上来一个。
于是这道题就做完了。
时间复杂度
/*https://www.cnblogs.com/hwy0622/p/17713057.html*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,W,len=0,w;
struct node{
int a,b,val;
bool operator <(const node &rhs) const{
return b<rhs.b;
}
}a[2005];
int f[50][1005];
signed main(){
/*2023.9.18 H_W_Y P3188 [HNOI2007] 梦幻岛宝珠 分组背包*/
while(scanf("%lld%lld",&n,&W)){
if(n==-1||W==-1) break;
for(int i=1;i<=n;i++){
scanf("%lld%lld",&w,&a[i].val);
a[i].a=w/(w&(-w));
a[i].b=0;
for(w=(w&(-w))>>1;w;w>>=1) a[i].b++;
}
memset(f,0,sizeof(f));
for(int j=0;j<=1000;j++) f[0][j]=0;
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)//直接枚举
for(int j=1000;j>=a[i].a;j--)
f[a[i].b][j]=max(f[a[i].b][j],f[a[i].b][j-a[i].a]+1ll*a[i].val);
len=0;
for(int s=W>>1;s;s>>=1) len++;
for(int i=1;i<=len;i++){
for(int j=1000;j>=0;j--)
for(int k=0;k<=j;k++)
f[i][j]=max(f[i][j],f[i-1][min(1000ll,(k<<1)|((W&(1<<(i-1)))!=0))]+f[i][j-k]); //必须要加上!=0
}
printf("%lld\n",f[len][1]);
}
return 0;
}
Conclusion
这道题有特殊性质,我们可以考虑把它分组。
在合并的时候注意上一个带上来的贡献……
思路还是挺妙的~
本文作者:H_W_Y
本文链接:https://www.cnblogs.com/H-W-Y/p/17713057.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步