洛谷P4095||bzoj3163 [HEOI2013]Eden 的新背包问题
https://www.luogu.org/problemnew/show/P4095
不太会。。
网上有神奇的做法:
第一种其实是暴力(复杂度3e8...)然而可以A。考虑多重背包,发现没有办法快速删除某个物品造成的贡献。考虑对于每个i,求出an1[i]和an2[i],分别表示对于[1,i]和[i,n]区间内所有物品的答案数组(如an1[i][j]表示[1,i]区间内用掉容量j可以带来的最大贡献),这个就是用普通多重背包求出来(可能要优化一下多重背包,以下用了二进制优化)。每次询问(x,y),就暴力枚举在[1,x-1]和[x+1,n]区间内分别取多少容量的物品,取最大贡献。复杂度O(n*log(c)*e+q*e)(如果用二进制优化多重背包)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int n,n1;
int c[],d[];
int lp[],rp[];
void work(int x,int y,int z)
{
//printf("1t%d %d %d %d\n",x,y,z,k);
++n1;x*=z;y*=z;
c[n1]=x;d[n1]=y;
//printf("1t%d %d\n",c[n1],d[n1]);
}
int qq;
int ans;//int ans[10010];
int an1[][];//an1[i][j]表示(前i个物品)j的容量最大价值
int an2[][];//i及之后的物品...
int main()
{
int i,j,x,y,z;
scanf("%d",&n);
for(i=;i<=n;++i)
{
scanf("%d%d%d",&x,&y,&z);
lp[i]=n1+;
for(j=;(j<<)-<=z;j<<=)
work(x,y,j);
if(z-j+) work(x,y,z-j+);
rp[i]=n1;
}
for(i=;i<=n1;++i)
{
memcpy(an1[i],an1[i-],sizeof(an1[i]));
for(j=;j>=c[i];--j)
an1[i][j]=max(an1[i][j],an1[i][j-c[i]]+d[i]);
}
for(i=n1;i>=;--i)
{
memcpy(an2[i],an2[i+],sizeof(an2[i]));
for(j=;j>=c[i];--j)
an2[i][j]=max(an2[i][j],an2[i][j-c[i]]+d[i]);
}
scanf("%d",&qq);
for(i=;i<=qq;++i)
{
scanf("%d%d",&x,&y);++x;
ans=;
for(j=;j<=y;++j)
ans=max(ans,an1[rp[x-]][j]+an2[lp[x+]][y-j]);
printf("%d\n",ans);
}
return ;
}
第二种是神奇的分治。注意到既不能快速删除多重背包中某个物品造成的贡献,又不能快速合并两个多重背包,但是可以快速向多重背包中加入一个物品。分治时维护一个多重背包的答案数组。solve(l,r),就先把[l,mid]内部的物品加入多重背包,然后solve(mid+1,r),再去掉[l,mid]内部物品造成的贡献(只需要恢复这一步操作之前的贡献数组即可),然后将[mid+1,r]内部的物品加入多重背包,solve(l,mid),去掉[mid+1,r]内部造成的贡献。这样当进行到solve(l,l)时就恰好只有l这个物品自身没有加入多重背包了,此时对于所有对这个位置的询问处理一下即可。复杂度O(n*log(c)*e*log(n)+q)(如果用二进制优化多重背包)(然而以下代码洛谷上跑的比“暴力”慢???)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
int n,n1;
int c[],d[];
int lp[],rp[];
void work(int x,int y,int z)
{
++n1;x*=z;y*=z;
c[n1]=x;d[n1]=y;
}
vector<pii> q[];
int qq;
int an[];int ans[];
void solve(int l,int r)
{
int i,j;
if(l==r)
{
for(i=;i<q[l].size();++i)
ans[q[l][i].se]=an[q[l][i].fi];
return;
}
int mid=l+((r-l)>>);
int an2[];
memcpy(an2,an,sizeof(an2));
for(i=lp[l];i<=rp[mid];++i)
for(j=;j>=c[i];--j)
an[j]=max(an[j],an[j-c[i]]+d[i]);
solve(mid+,r);
memcpy(an,an2,sizeof(an));
for(i=lp[mid+];i<=rp[r];++i)
for(j=;j>=c[i];--j)
an[j]=max(an[j],an[j-c[i]]+d[i]);
solve(l,mid);
memcpy(an,an2,sizeof(an));
}
int main()
{
int i,j,x,y,z;
scanf("%d",&n);
for(i=;i<=n;++i)
{
scanf("%d%d%d",&x,&y,&z);
lp[i]=n1+;
for(j=;(j<<)-<=z;j<<=)
work(x,y,j);
if(z-j+) work(x,y,z-j+);
rp[i]=n1;
}
scanf("%d",&qq);
for(i=;i<=qq;++i)
{
scanf("%d%d",&x,&y);++x;
q[x].pb(pii(y,i));
}
solve(,n);
for(i=;i<=qq;++i)
printf("%d\n",ans[i]);
return ;
}
洛谷P4095||bzoj3163 [HEOI2013]Eden 的新背包问题的更多相关文章
- bzoj3163: [Heoi2013]Eden的新背包问题
Description “寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心心静,能不能说给我听.”失忆的Eden总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她 ...
- P4095 [HEOI2013]Eden 的新背包问题
P4095 [HEOI2013]Eden 的新背包问题 题解 既然假定第 i 个物品不可以选,那么我们就设置两个数组 dpl[][] 正序选前i个物品,dpr[][] 倒序选前i个物品 ,价格不超过 ...
- BZOJ3163&Codevs1886: [Heoi2013]Eden的新背包问题[分治优化dp]
3163: [Heoi2013]Eden的新背包问题 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 428 Solved: 277[Submit][ ...
- BZOJ 3163: [Heoi2013]Eden的新背包问题( 背包dp )
从左到右, 从右到左分别dp一次, 然后就可以回答询问了. ---------------------------------------------------------- #include< ...
- luogu P4095 [HEOI2013]Eden 的新背包问题 多重背包 背包的合并
LINK:Eden 的新背包问题 就是一个多重背包 每次去掉一个物品 询问钱数为w所能买到的最大值. 可以对于每次Q暴力dp 利用单调队列优化多重背包 这样复杂度是Qnm的. 发现过不了n==10的点 ...
- 题解——洛谷P4095 [HEOI2013]Eden 的新背包问题(背包)
思路很妙的背包 用了一些前缀和的思想 去掉了一个物品,我们可以从前i-1个和后i+1个推出答案 奇妙的思路 #include <cstdio> #include <algorithm ...
- LUOGU P4095 [HEOI2013]Eden 的新背包问题
题目描述 " 寄 没 有 地 址 的 信 ,这 样 的 情 绪 有 种 距 离 ,你 放 着 谁 的 歌 曲 ,是 怎 样 的 心 情 . 能 不 能 说 给 我 听 ." 失忆的 ...
- Luogu P4095 [HEOI2013]Eden 的新背包问题 思维/动规
当时一直在想前缀和...多亏张队提醒... 从1到n背次包,保存每一个状态下的价值,就是不要把第一维压掉:再从n到1背一次,同样记住每种状态: 然后询问时相当于是max(前缀+后缀),当然前缀后缀中间 ...
- Luogu P4095 [HEOI2013]Eden的新背包问题
题目 求出从前往后的背包\(f_{i,j}\)和从后往前的背包\(F_{i,j}\). 那么对于询问\((d,e)\),答案就是\(\max\limits_{i=0}^e f_{d-1,i}+F_{d ...
随机推荐
- C++打印变量地址
%p专门用来打印变量的以十六进制表示的地址: #include<iostream> using namespace std; int main() { ; printf("a的地 ...
- python并发编程之多线程理论部分
阅读目录 一 什么是线程 二 线程的创建开销小 三 线程与进程的区别 四 为何要用多线程 五 多线程的应用举例 六 经典的线程模型(了解) 七 POSIX线程(了解) 八 在用户空间实现的线程(了解) ...
- html5--4-2 video元素的属性
html5--4-2 video元素的属性 学习要点 掌握video元素的基本用法 直到现在,在网页中的大多数视频是通过插件(比如 Flash)来显示的.然而,并非所有浏览器都拥有同样的插件.HTML ...
- python 基础之第三天
例子1:8位数的随机密码 #!/usr/bin/python # coding:utf-8 import string import random pwd = '' for i in range(8) ...
- bzoj 4289 PA2012 Tax——构图
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 可以把一个点上的边按权值排序,然后边权小的向第一个比它大的连差值的边,边权大的向第一个 ...
- 通过libVirt抓取kvm虚拟机监控指标数据
通常在我们的云环境中,为了保证云平台中虚拟机的正常运行,基本都需要这样一个功能,就是收集虚拟机的监控数据,比如cpu的使用率.内存的使用率.磁盘io.网络io等基本信息.可以利用这些信息及时调整云平台 ...
- 2014年将会受欢迎的IT技能--你有多少哪?
据国外媒体报道,据Global Knowledge等十几家研究机构发布的2014年IT技能和薪金调查报告显示,2014年最受欢迎的十大IT技能如下: 1.编程与应用开发 据美国劳工统计局称,开发者和程 ...
- P2P通讯初步实现
原文URL: http://www.cnblogs.com/dlwang2002/archive/2008/09/16/1291793.html 1:基于Socket连接: 2:在四个局域网内测试通过 ...
- 3-C++程序的结构1.1
数据的共享和保护机制是C++的重要特性之一. 1.标识符的作用域与可见性 作用域讨论的是标识符的有效范围,可见性是讨论标识符是否可以被引用. a.作用域 作用域是一个标识符在程序正文中有效的区域.C+ ...
- java集合框架之几种set(HashSet LinkedHashSet TreeSet )
参考http://how2j.cn/k/collection/collection-sets/691.html#nowhere HashSet LinkedHashSet TreeSet HashSe ...