题目链接:

http://codeforces.com/contest/808/problem/E

题目大意:

  Petya 有 n 个纪念品,他能带的最大的重量为 m,各个纪念品的重量为 wi,花费为 ci,问 Petya 能带的纪念品的最大价值几何?

心得:

  刚开始以为是01背包,开开心心地写了个dp上去超时ORZ。后来想要用记忆化,发现开不出这么大的数组,所以想了很久也想不出个所以然。

  后来经一位大神一篇博文的点拨(链接:http://www.cnblogs.com/wmrv587/p/6876314.html),决定用三分法试试。

  于是看了一篇介绍三分查找的博文(链接:http://blog.csdn.net/pi9nc/article/details/9666627)

  然后动手写了第一版代码:

 #include <cstdio>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXN=+;
int cost[][MAXN];
int t[];
int n,m;
long long sum[][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
int k;
scanf("%d",&k);
scanf("%d",&cost[k][++t[k]]);
}
for(int i=;i<=;i++) sort(cost[i]+,cost[i]+t[i]+,greater<int>()); for(int i=;i<=;i++)
for(int j=;j<=t[i];j++)
sum[i][j]=sum[i][j-]+cost[i][j];
long long ans=;
for(int i=;i<=m;i++){
int l=,r=min(t[],i/); //以2重量的来计算
while(l<r){
int mid=(l+r)/,mmid=(mid+r)/;
int t11=min(i-mid*,t[]),t12=min(i-mmid*,t[]);
if(sum[][mid]+sum[][t11]>sum[][mmid]+sum[][t12])
r=mmid;
else
l=mid+;
}
int t1=min(i-l*,t[]);
long long temp=sum[][l]+sum[][t1];
int t3=min(t[],(m-i)/);
temp+=sum[][t3];
ans=max(ans,temp);
}
printf("%I64d\n",ans);
return ;
}

  结果Wrong answer on test 8。

  在那里debug了2个小时,把它改成了这样:

 #include <cstdio>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXN=+;
int cost[][MAXN];
int t[];
int n,m;
long long sum[][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
int k;
scanf("%d",&k);
scanf("%d",&cost[k][++t[k]]);
}
for(int i=;i<=;i++) sort(cost[i]+,cost[i]+t[i]+,greater<int>()); for(int i=;i<=;i++)
for(int j=;j<=t[i];j++)
sum[i][j]=sum[i][j-]+cost[i][j]; long long ans=;
for(int i=;i<=m;i++){
int l=,r=min(t[],i/); //以2重量的来计算
for(int k=;k<;k++){
int mid=(l+r)/,mmid=(mid+r)/;
if(sum[][mid]+sum[][i-mid*]>=sum[][mmid]+sum[][i-mmid*])
r=mmid;
else
l=mid;
}
int t1=min(i-l*,t[]);
long long temp=sum[][l]+sum[][t1];
int t3=min(t[],(m-l*-t1)/);
temp+=sum[][t3];
ans=max(ans,temp);
}
printf("%I64d\n",ans);
return ;
}

  但还是WA。

  于是去参考排行榜上很靠前的一位选手的做法,发现其中一位的做法跟我很相似,但是他在 l-r<=30 的时候就停止了三分查找,然后再遍历 [l,r] 这个区间,找出最优解。

  仿照这个做法,我写了第三个版本:

 #include <cstdio>
#include <algorithm>
#include <functional>
using namespace std;
const int MAXN=+;
int cost[][MAXN];
int t[];
int n,m;
long long sum[][MAXN];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
int k;
scanf("%d",&k);
scanf("%d",&cost[k][++t[k]]);
}
for(int i=;i<=;i++) sort(cost[i]+,cost[i]+t[i]+,greater<int>()); for(int i=;i<=;i++)
for(int j=;j<=t[i];j++)
sum[i][j]=sum[i][j-]+cost[i][j]; long long ans=;
for(int i=;i<=m;i++){
int l=,r=min(t[],i/);
while(r-l>){
int mid=(l+r)/,mmid=(mid+r)/;
if(sum[][mid]+sum[][i-mid*]>=sum[][mmid]+sum[][i-mmid*])
r=mmid;
else
l=mid;
}
int t1=min(t[],i-*l);
long long maxc=sum[][l]+sum[][t1];
int maxn=l,maxm=t1+l*;
for(int j=l+;j<=r;j++){
int tt1=min(t[],i-*j);
if(sum[][j]+sum[][tt1]>maxc){
maxn=j;
maxc=sum[][j]+sum[][tt1];
maxm=j*+tt1;
}
}
long long temp=maxc;
int t3=min(t[],(m-maxm)/);
temp+=sum[][t3];
ans=max(ans,temp);
}
printf("%I64d\n",ans);
return ;
}

  终于AC了!

  后来研究发现,用最后一种作法,在三分得出的区间内得出的峰值跟直接三分得到的峰值并不一致。

  

  拓展思考:以后当发现直接三分(二分)查找得出的结果有问题时,可尝试先找出一个区间即可,在这个区间里遍历找出最优解。

  

  

  

CF808E Selling Souvenirs的更多相关文章

  1. Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)

    E. Selling Souvenirs time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  2. Codeforces 808 E. Selling Souvenirs(三分)

    E. Selling Souvenirs 题意: n件物品,有重量和价值,重量只有三种1,2,3.问取不超过m重量的物品的价值总和最大是多少.(n<=1e5,w<=3e5) 思路: n*w ...

  3. E. Selling Souvenirs 不会做

    http://codeforces.com/contest/808/problem/E 不理解为什么dp = {cost, cnt1, cnt2}可以 而dp = {cost, cnt1, cnt2, ...

  4. Educational Codeforces Round 21E selling souvenirs (dp)

    传送门 题意 给出n个体积为wi,价值为ci的物品,现在有一个m大的背包 问如何装使得最后背包内的物品价值最大,输出价值 分析 一般的思路是01背包,但n*v不可做 题解的思路 We can iter ...

  5. 【dp】E. Selling Souvenirs

    http://codeforces.com/contest/808/problem/E 题意:给定n个重量为可能1,2,3的纪念品和各自的价值,问在背包总重量不超过m的条件下总价值最大为多少. 其中1 ...

  6. codeforces 808 E. Selling Souvenirs (dp+二分+思维)

    题目链接:http://codeforces.com/contest/808/problem/E 题意:最多有100000个物品最大能放下300000的背包,每个物品都有权值和重量,为能够带的最大权值 ...

  7. Educational Codeforces Round 21

    Educational Codeforces Round 21  A. Lucky Year 个位数直接输出\(1\) 否则,假设\(n\)十进制最高位的值为\(s\),答案就是\(s-(n\mod ...

  8. [HDU 2126] Buy the souvenirs (动态规划)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给你n个物品,m元钱,问你最多能买个多少物品,并且有多少种解决方案. 一开始想到的是,先解 ...

  9. HDU 2126 Buy the souvenirs (01背包,输出方案数)

    题意:给出t组数据 每组数据给出n和m,n代表商品个数,m代表你所拥有的钱,然后给出n个商品的价值 问你所能买到的最大件数,和对应的方案数.思路: 如果将物品的价格看做容量,将它的件数1看做价值的话, ...

随机推荐

  1. 听说你在从事前端开发?那这10个JavaScript的优化问题你不得不知道!

    JavaScript的高效优化一直都是我们前端开发中非常重要的工作,也是很多开发人员无法做好的一部分内容,今天我总结了10个优化问题,大家可以参考来做优化,这其中很多问题都是大家经常遇到的哦. ==和 ...

  2. composer+psr-4实现自动加载

    自动加载 对于库的自动加载信息,Composer 生成了一个 vendor/autoload.php 文件.你可以简单的引入这个文件,你会得到一个免费的自动加载支持. require 'vendor/ ...

  3. 搭建vsftpd文件服务器并创建虚拟用户

    一.安装     1. 查看是否安装vsftpd         rpm -qa | grep vsftpd     2. 安装          yum -y install vsftpd      ...

  4. Tomcat 8 Host-Manager配置访问的方法,全网唯一正确配置

    2019独角兽企业重金招聘Python工程师标准>>> 环境: 操作系统:         Linux version 2.6.32-696.10.1.el6.x86_64 (moc ...

  5. MYSQL 排序和分组

    一.MYSQL 中有两种排序方式: 1:通过有序索引顺序扫描直接返回有序数据,这种方式在使用explain 分析查询的时候显示为Using Index ,不需要额外的排序,操作效率较高. 2: 是通过 ...

  6. unittest(简介)

    一.unittest框架介绍: unittest框架是python中的一个单元测试框架,该模块包括许多的类如 TestCase 类.TestSuite 类.TextTestRunner 类.TestR ...

  7. 一个poll的简单例子

    该程序使用poll事件机制实现了一个简单的消息回显的功能,其服务器端和客户端的代码如下所示: 服务器端: //start from the very beginning,and to create g ...

  8. 初次认识Ngnix

    这几天写那个HTTPD,最后觉得学到的好像很少,而且就算最后运行成功了好像也没有什么.所以想学习一些生活中真正在运用着的web服务器, 上网查询了些资料了解到apache, lighttpd, ngi ...

  9. 纯django开发最完美博客

    2020年5月打造最时尚博客系统教程 为了学习速度,集中精力学习django和博客开发, 没有使用其它框架,也没有使用css预处理等 这样学起来最方便, 博客前后端都完成, www.duanshuil ...

  10. Haporxy

    安装Haproxy: 下载 wget https://fossies.org/linux/misc/haproxy-1.8.3.tar.gz tar -zxf haproxy-.tar.g cd ha ...