CF808E Selling Souvenirs
题目链接:
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的更多相关文章
- Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)
E. Selling Souvenirs time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces 808 E. Selling Souvenirs(三分)
E. Selling Souvenirs 题意: n件物品,有重量和价值,重量只有三种1,2,3.问取不超过m重量的物品的价值总和最大是多少.(n<=1e5,w<=3e5) 思路: n*w ...
- E. Selling Souvenirs 不会做
http://codeforces.com/contest/808/problem/E 不理解为什么dp = {cost, cnt1, cnt2}可以 而dp = {cost, cnt1, cnt2, ...
- Educational Codeforces Round 21E selling souvenirs (dp)
传送门 题意 给出n个体积为wi,价值为ci的物品,现在有一个m大的背包 问如何装使得最后背包内的物品价值最大,输出价值 分析 一般的思路是01背包,但n*v不可做 题解的思路 We can iter ...
- 【dp】E. Selling Souvenirs
http://codeforces.com/contest/808/problem/E 题意:给定n个重量为可能1,2,3的纪念品和各自的价值,问在背包总重量不超过m的条件下总价值最大为多少. 其中1 ...
- codeforces 808 E. Selling Souvenirs (dp+二分+思维)
题目链接:http://codeforces.com/contest/808/problem/E 题意:最多有100000个物品最大能放下300000的背包,每个物品都有权值和重量,为能够带的最大权值 ...
- Educational Codeforces Round 21
Educational Codeforces Round 21 A. Lucky Year 个位数直接输出\(1\) 否则,假设\(n\)十进制最高位的值为\(s\),答案就是\(s-(n\mod ...
- [HDU 2126] Buy the souvenirs (动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2126 题意:给你n个物品,m元钱,问你最多能买个多少物品,并且有多少种解决方案. 一开始想到的是,先解 ...
- HDU 2126 Buy the souvenirs (01背包,输出方案数)
题意:给出t组数据 每组数据给出n和m,n代表商品个数,m代表你所拥有的钱,然后给出n个商品的价值 问你所能买到的最大件数,和对应的方案数.思路: 如果将物品的价格看做容量,将它的件数1看做价值的话, ...
随机推荐
- String、String[]、ArrayList<String>之间的转换
1. ArrayList<String> 转换为 String[]: ArrayList<String> list = new ArrayList<>(); li ...
- HTML 教程之常用html标签
前端三把利器: HTML:赤裸裸的人 20个标签 CSS:华丽的衣服 颜色 位置 …… JS:让这个人动起来 一.HTML本质及在web程序中的作用 web访问中,浏览器充当一个socket客户端. ...
- Condition的await()和signal()流程
介绍 Condition是j.u.c包下提供的一个接口. 可以翻译成 条件对象,其作用是线程先等待,当外部满足某一条件时,在通过条件对象唤醒等待的线程.ArrayBlockingQueue就是通过Co ...
- AbstractQueuedSynchronizer与ReentrantLock
介绍 j.u.c包中的Lock定义了锁的行为. 而ReentrantLock是并发包下提供的一个锁的实现,它是一个可重入的.排他的锁. ReentrantLock有的属性也很简单,除了一个serial ...
- 手把手教你用Node.js爬虫爬取网站数据
个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 开始之前请先确保自己安装了Node.js环境,还没有安装的的童鞋请自行百度 ...
- 一个poll的简单例子
该程序使用poll事件机制实现了一个简单的消息回显的功能,其服务器端和客户端的代码如下所示: 服务器端: //start from the very beginning,and to create g ...
- 【Python】Django2.0集成Celery4.1详解
环境准备 Python3.6 pip install Django==2.0.1 pip install celery==4.1.0 pip install eventlet (加入协程支持) 安装e ...
- 数据可视化:使用python代码实现可视数据随机漫步图
#2020/4/5 ,是开博的第一天,希望和大家相互交流学习,很开森,哈哈~ #像个傻子哟~ #好,我们进入正题, #实现功能:利用python实现数据随机漫步,漫步点数据可视化 #什么是 ...
- NLP(二十九)一步一步,理解Self-Attention
本文大部分内容翻译自Illustrated Self-Attention, Step-by-step guide to self-attention with illustrations and ...
- python 读hdf4文件,再转写成一个tif文件
1.安装pyhdf包 (1)通过此链接查找并下载pyhdf包:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame(根据自己的系统及python版本选择 ...