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 的新背包问题的更多相关文章

  1. bzoj3163: [Heoi2013]Eden的新背包问题

    Description “寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心心静,能不能说给我听.”失忆的Eden总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她 ...

  2. P4095 [HEOI2013]Eden 的新背包问题

    P4095 [HEOI2013]Eden 的新背包问题 题解 既然假定第 i 个物品不可以选,那么我们就设置两个数组 dpl[][] 正序选前i个物品,dpr[][] 倒序选前i个物品 ,价格不超过 ...

  3. BZOJ3163&Codevs1886: [Heoi2013]Eden的新背包问题[分治优化dp]

    3163: [Heoi2013]Eden的新背包问题 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 428  Solved: 277[Submit][ ...

  4. BZOJ 3163: [Heoi2013]Eden的新背包问题( 背包dp )

    从左到右, 从右到左分别dp一次, 然后就可以回答询问了. ---------------------------------------------------------- #include< ...

  5. luogu P4095 [HEOI2013]Eden 的新背包问题 多重背包 背包的合并

    LINK:Eden 的新背包问题 就是一个多重背包 每次去掉一个物品 询问钱数为w所能买到的最大值. 可以对于每次Q暴力dp 利用单调队列优化多重背包 这样复杂度是Qnm的. 发现过不了n==10的点 ...

  6. 题解——洛谷P4095 [HEOI2013]Eden 的新背包问题(背包)

    思路很妙的背包 用了一些前缀和的思想 去掉了一个物品,我们可以从前i-1个和后i+1个推出答案 奇妙的思路 #include <cstdio> #include <algorithm ...

  7. LUOGU P4095 [HEOI2013]Eden 的新背包问题

    题目描述 " 寄 没 有 地 址 的 信 ,这 样 的 情 绪 有 种 距 离 ,你 放 着 谁 的 歌 曲 ,是 怎 样 的 心 情 . 能 不 能 说 给 我 听 ." 失忆的 ...

  8. Luogu P4095 [HEOI2013]Eden 的新背包问题 思维/动规

    当时一直在想前缀和...多亏张队提醒... 从1到n背次包,保存每一个状态下的价值,就是不要把第一维压掉:再从n到1背一次,同样记住每种状态: 然后询问时相当于是max(前缀+后缀),当然前缀后缀中间 ...

  9. Luogu P4095 [HEOI2013]Eden的新背包问题

    题目 求出从前往后的背包\(f_{i,j}\)和从后往前的背包\(F_{i,j}\). 那么对于询问\((d,e)\),答案就是\(\max\limits_{i=0}^e f_{d-1,i}+F_{d ...

随机推荐

  1. 在react jsx中,为什么使用箭头函数和bind容易出现问题

    在之前的文章中,已经说明如何避免在react jsx中使用箭头函数和bind(https://medium.freecodecamp.o... 但是没有提供一个清晰的demo展示为什么要这样做. 现在 ...

  2. shell动态变量

    面对变量中嵌套变量,可以这么做 other_devops_ip="......." options='_ip' tennat_name='other_devops' tennat_ ...

  3. 确定mapkeeper使用的leverdb库路径

    目前libleveldb的a或so库有三个路径,/usr/lib, /usr/lib/x86_64-linux-gnu , /usr/local/lib 使用 ls -d -1 /usr/lib/*  ...

  4. 详解linux中install命令和cp命令的区别

    基本上,在Makefile里会用到install,其他地方会用cp命令. 它们完成同样的任务——拷贝文件,它们之间的区别主要如下: .最重要的一点,如果目标文件存在,cp会先清空文件后往里写入新文件, ...

  5. HihoCoder 1502 : 最大子矩阵 (双指针)

    描述 给定一个NxM的矩阵A和一个整数K,小Hi希望你能求出其中最大(元素数目最多)的子矩阵,并且该子矩阵中所有元素的和不超过K. 输入 第一行包含三个整数N.M和K. 以下N行每行包含M个整数,表示 ...

  6. python BaseManager分布式学习

    如果我们已经有一个通过Queue通信的多进程程序在同一台机器上运行,现在,由于处理任务的进程任务繁重,希望把发送任务的进程和处理任务的进程分布到两台机器上.怎么用分布式进程实现?原有的Queue可以继 ...

  7. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

  8. HTML head元素

    head标签中可以包含的标签元素有: <title>:定义html页面的标题 <meta>: <meta> 标签提供了元数据.元数据也不显示在页面上,但会被浏览器解 ...

  9. U盘安装 Linux 显示 “Faild to copy file from CD-ROM”

    解决方案 使用 UltraISO 刻录 U盘做镜像时,出现这种情况.查阅别人的 blog,尝试手动挂载发现还是不能成功.然后使用 win32diskimager 重新刻录,再次安装时未出现该情况. 参 ...

  10. Flutter实战视频-移动电商-04.底部导航栏切换效果

    04.底部导航栏切换效果 博客地址: https://jspang.com/post/FlutterShop.html#toc-291 我们要做的效果图: 新建四个页面 home_page.dart ...