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. Android studio在ubuntu下安装【转】

    本文转载自:http://www.jianshu.com/p/776e3b52e930 这学期的Android课程要学Android比较底层的东西,所以老师要求在Linux下安装Android的开发环 ...

  2. hihocoder #1094 : Lost in the City微软苏州校招笔试 12月27日 (建图不大【暴力枚举】 子图的4种形态 1Y )

    #1094 : Lost in the City 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Little Hi gets lost in the city. He ...

  3. Android设备管理器 DevicePolicyManager

    设备管理器有个特点,你注册了之后如果不解除注册就会难以卸载带有设备管理器的应用,目前4.3版本仍未提示用户如何卸载,maybe later. 在「设定-安全」你可以看见「设备管理器」,它提供一些高级功 ...

  4. React.js 之hello word

    引入的js文件说明 react.js 是 React 的核心库 react-dom.js 是提供与 DOM 相关的功能 babel.min.js的作用是将 JSX 语法转为 JavaScript 语法 ...

  5. SPOJcot2 Count on a tree II (树上莫队)

    You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer ...

  6. leetcode 395 至少有K个重复字符的最长子串

    找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k .输出 T 的长度. 示例 1: 输入: s = "aaabb", k = 3 输 ...

  7. 苹果app(iOS app)的URL schemes

    最近折腾iOS快捷启动应用或应用内的某个动作的神器launch center pro (LCP),发现很多国产app并没有被LCP官方收录,所以不得不想办法找到app的url schemes. 下面是 ...

  8. initWithFrame 与 initWithCoder 、awakeFromNib 的方法理解笔记

    1. initWithFrame方法是什么? initWithFrame方法用来初始化并返回一个新的视图对象,根据指定的CGRect(尺寸). 当然,其他UI对象,也有initWithFrame方法, ...

  9. python --Eclipse中安装pydev插件及调试

    运行程序 运行 Python 源程序,有两种方法,以 example.py 为例: example.py代码: #!/usr/bin/env python # -*- coding:utf-8 -*- ...

  10. 【转载】“error LNK1169: 找到一个或多个多重定义的符号”的解决方法

    c++的小细节的地方 原文地址:https://blog.csdn.net/xiaosu123/article/details/5665729 问题描述如下: 有 三个源文件,A.h.B.cpp.C. ...