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看做价值的话, ...
随机推荐
- 后缀数组SA
复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...
- web 之 session
Session? 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务器程序可以 ...
- 【Linux常见命令】rm命令
rm - remove files or directories rm命令用于删除一个文件或者目录. 语法: rm [OPTION]... FILE... 参数: -f 强制删除文件 -r 递归,用于 ...
- 日日算法:Dijkstra算法
介绍 Dijistra算法作为一种最短路径算法,可以用来计算一个节点到图上其他节点的最短距离. 主要是通过启发式的思想,由中心节点层层向外拓展,直到找到中点. 适用于无向图和有向图. 算法思想 假设我 ...
- Java反射与注解
反射 能够分析类能力的程序称为反射(reflective),代码的这种能力称为"自省".反射机制的功能极其强大,反射机制可以用来: 在运行时分析类的能力 在运行时查看对象,例如,编 ...
- 国际站中国区,孟买上Redis 4.0 集群版
信息摘要: 国际站中国区,孟买上线Redis 4.0 集群版适用客户: 所有用户版本/规格功能: redis 4.0 集群版产品文档: https://www.alibabacloud.com/hel ...
- RxJava2源码解析(二)
title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...
- P1459 三值的排序 Sorting a Three-Valued
题目描述 排序是一种很频繁的计算任务.现在考虑最多只有三值的排序问题.一个实际的例子是,当我们给某项竞赛的优胜者按金银铜牌排序的时候.在这个任务中可能的值只有三种1,2和3.我们用交换的方法把他排成升 ...
- python(json 模块)
1.Json 定义 定义:JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.JSON 的数据格式其实就是 python 里面的字典格式,里 ...
- C++ 函数重载,函数模板和函数模板重载,选择哪一个?
重载解析 在C++中,对于函数重载.函数模板和函数模板重载,C++需要有一个良好的策略,去选择调用哪一个函数定义(尤其是多个参数时),这个过程称为重载解析. (这个过程将会非常复杂,但愿不要遇到一定要 ...