题目链接:

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. pfSense®2.4.4发布后,原pfSense 黄金会员的服务将免费使用!

    2018年7月16日,Doug McIntire 从即将发布的pfSense®2.4.4开始,之前在"pfSense Gold"下提供的所有服务都将继续,但所有pfSense用户都 ...

  2. DeepWalk论文精读:(3)实验

    模块三 1 实验设计 1.1 数据集 BLOGCATALOG[39]:博客作者网络.标签为作者感兴趣的主题. FLICKR[39]:照片分享网站的用户网络.标签为用户的兴趣群组,如"黑白照片 ...

  3. C++类学习(2)

    Ⅰ:类概念 一:类的构成 class 类名 { public: 公有数据成员和成员函数:类的接口 protected: 保护数据成员和成员函数: private: 私有数据成员和成员函数: }://注 ...

  4. 使用C++STL的map容器实现一种命令映射

    因为最近在练习写一个ftp的服务器,其中的命令有很多种,每个命令对应一个执行函数,能够想到的最简单的实现方式便是使用if--else匹配命令和执行对应的函数,如下所示: if(strcmp(" ...

  5. 实现MapReduce

    简介 当我们要统计数亿文本的词频,单个机器性能一般,况且是数亿级数据,处理是十分缓慢的,对于这样的任务,希望的是多台电脑共同处理,大幅度减少任务时间.联合多台电脑一起工作的系统就是分布式系统. 最近在 ...

  6. FMT/FWT学习笔记

    目录 FMT/FWT学习笔记 FMT 快速莫比乌斯变换 OR卷积 AND卷积 快速沃尔什变换(FWT/XOR卷积) FMT/FWT学习笔记 FMT/FWT是算法竞赛中求or/and/xor卷积的算法, ...

  7. Django model重写save方法及update踩坑记录

    一个非常实用的小方法 试想一下,Django中如果我们想对保存进数据库的数据做校验,有哪些实现的方法? 我们可以在view中去处理,每当view接收请求,就对提交的数据做校验,校验不通过直接返回错误, ...

  8. 使用 if elseif else 指定条件

    nrows = 4; ncols = 6; A = ones(nrows,ncols); 遍历矩阵并为每个元素指定一个新值.对主对角线赋值 2,对相邻对角线赋值 -1,对其他位置赋值 0. for c ...

  9. Python3中正则的贪婪匹配模式

    什么是贪婪模式 正则在进行匹配时,从开始位置查找最远的结束位置,这种模式称之为贪婪模式. 在进行HTML标签类似内容获取时,贪婪模式会导致整个内容的返回,需要使用非贪婪模式. 固定的书写规则 : .* ...

  10. [hdu5418 Victor and World]floyd + 状压DP 或 SPFA

    题意:给n个点,m条边,每次只能沿边走,花费为边权值,求从1出发经过所有其它点≥1次最后回到1的最小花费. 思路: 状压DP.先用Floyd得到任意两点间的最短距离,转移时沿两个点的最短路转移.此时的 ...