题目链接:

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. MAC攻击及缺陷

    MAC攻击及缺陷 MAC有好几种实现方式 对MAC的攻击 重放攻击 重放攻击的防护 密钥推测攻击 MAC算法的缺陷 第三方证明 防止否认 前面我们在讲HMAC的时候简单讲过了什么是MAC消息认证码. ...

  2. 数学--数论--整除分块(巨TM详细,学不会,你来打我)

    1.概念 从一道例题说起 在介绍整除分块之前,我们先来看一道算数题:已知正整数n,求∑i=1n⌊ni⌋已知正整数n,求∑i=1n⌊ni⌋在介绍整除分块之前,我们先来看一道算数题: 已知正整数n,求∑i ...

  3. HDU - 6187 (最大生成树) 最小生成树

    Destroy Walls Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) ...

  4. 题目分享G 二代目

    题意:有n组数,每组包含两个数,问在每组只能取一个的前提下能组成的最长的从1开始的连续自然数有几个? 分析:刚学了差分约束系统,很容易往转换成图的方向去想 将他读入的这n组数当成边读入 很容易会得到一 ...

  5. aws mysql 开启慢查询日志, 并利用mysqlsla 分析

    1.开启慢查询日志服务 (a) sql 查询配置 # 查看慢日志是否开启,开启为ON show variables like 'slow_query%'; show variables like 'l ...

  6. sequel pro无法连接mysql服务器

    1. 添加用户 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_passwd' WITH GRANT OPTION; FLU ...

  7. JavaScript键值对集合怎么使用

    JavaScript键值对集合怎么使用 我们可以对此键值对集合分为3种难度 1.简单的使用 var arr = { 'cn': "中国", 'usa': '美国', 'jp': ' ...

  8. P3983 赛斯石(双背包)

    这题不算难的,但是脑子真的特别乱.....传送门 \(Ⅰ.物品可以拆开来但船不能拆开来,所以1-10载重船的最大收益完全可以用背包求出来.\) \(Ⅱ.最后一定是选一些船走,而船的收益已经固定.所以用 ...

  9. C - 小明系列故事――捉迷藏 HDU - 4528 bfs +状压 旅游-- 最短路+状压

    C - 小明系列故事――捉迷藏 HDU - 4528 这个题目看了一下题解,感觉没有很难,应该是可以自己敲出来的,感觉自己好蠢... 这个是一个bfs 用bfs就很好写了,首先可以预处理出大明和二明能 ...

  10. CSS的基础使用

    一,css是什么? CSS全称为“层叠样式表” ,与HTML相辅相成,实现网页的排版布局与样式美化 二,CSS使用方式 1.行内样式/内联样式(单一页面中使用) 借助于style标签属性,为当前的标签 ...