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. RequireJS 加载 js 执行顺序

    初次接触RequireJS 对文档理解不很透彻,自己通过测试测到的执行顺序: 文档结构: |-amaze | -js | -amazeui.js | -jquery.min.js | -main.js ...

  2. 百度地图API简单应用——1.根据地址查询经纬度

    这几天比较空闲,就接触了下百度地图的API(开发者中心链接地址:http://developer.baidu.com),发现调用还是挺方便的.只要简单几步注册下,就可以获得一个Key,就能直接调用(P ...

  3. Android之styles.xml,以及自定义风格

    1.styles.xml 在现在的ADT创建的Project中,会有values,values-v11和values-v14三个文件夹,每个文件夹下都有一个styles.xml. API11是Andr ...

  4. CodeForces - 840D:(主席树求出现区间出现次数大于某值的最小数)

    Once, Leha found in the left pocket an array consisting of n integers, and in the right pocket q que ...

  5. Linux-Bond-Configure

    Centos 6.6 1. modify /etc/modprobe.d/bond.conf alias bond0 bonding 2. config eth0 & eth1 cat /et ...

  6. PowerDesigner 把Comment写到name中 和把name写到Comment中

    在使用PowerDesigner对数据库进行概念模型和物理模型设计时,一般在NAME或Comment中写中文,在Code中写英文.Name用来显 示,Code在代码中使用,但Comment中的文字会保 ...

  7. hihoCoder2月29日(字符串模拟)

    时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 只有闰年有2月29日,满足以下一个条件的年份为闰年: ...

  8. 在xshell中使用Linux语言打开错误提示

    上线项目到服务器后, 有时候有的功能跟本地调试的不一样,这时候就需要设置打开display_errors = On: 首先,cd .. 进入上一级,ll 罗列当前目录,跟home当前目录的有这个usr ...

  9. Google浏览器如何加载本地文件

    Chrome浏览器加载本地文件 一般来说,为了安全起见,浏览器是不能通过load方法来加载本地文件的,load方法只能加载远程服务器上的文件. 在浏览器默认的情况下,试图加载一个本地文件,会出现交叉域 ...

  10. 【网络爬虫】【java】微博爬虫(三):庖丁解牛——HTML结构分析与正则切分

    在上一篇文章中已经通过请求的url地址把html页面爬取下来了,这里分别以网易微博的html和新浪微博的html为例来分析如何提取微博数据. 一.网易微博解析 相比新浪微博的html结构,网易微博的比 ...