P2672 推销员 优先队列 + 贪心
题解:
我会说我想这道普及组题都想了好久么。。。。
不熟练的普及组选手.jpg
最后随便猜了一个结论居然是对的。。。
放结论:
假设x = i的最优决策为f[i], 那么f[i + 1]一定包括f[i].
也就是说f[i+1]一定可以由f[i]推出来。
所以f[i]一定是由f[i+1]中选定的所有点中去掉一个得来的。
即下一次选择一定是基于上一次选择的。。。
至于证明嘛。。。感性理解吧。
因为选哪户人家推销其实相互没太多联系。而且选i个推销肯定选满是最划得来的。。。。
大概是这么理解的吧。(反向理解可能更加好理解一点)
所以有了这个结论就很好解决了。
因为f[n]的最优决策肯定是n个点全选。
所以我们从这个已知的往前推。
于是我们来观察这n个点,到底删掉哪个减掉的疲劳值最小呢?
首先选中的这些点可以看做一个有序点集,位置由s[i]的大小所决定。
因此我们记last[x]为在x前面的第一个点的id, Next[x]为在x后面的第一个点的id。
于是有两种情况:
1,删去的点在末尾。
此时减掉的疲劳值为a[x] + 2 * (s[x] - s[last[x]])
2,删去的点在中间。
那么此时对走路的距离没有任何影响,因此我们只需要减a[x]即可。
值得注意的是,当末尾点k为a[i]最小的点时, 我们需要再取出次小的点来做比较,因为a[k]虽然最小,但由于要走很多路,所以a[k] + 2 * (s[k] - s[last[k]])并不一定小于a[i](i < k, 且i ∈ 点集),因此我们需要进一步比较再做取舍。
而k不是a[i]最小的点时,因为a[k]就已经大于a[i]了,所以减去的疲劳值肯定要大于a[i]了,因此直接删最小的点就可以了。
这里的最小和次小由于要支持插入,删除,查询,因此我们使用优先队列来实现。
为了方便查询元素的id,,,于是我又建了一个结构体、。
代码:
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define LL long long
#define getchar() *o++
#define AC 100100
char READ[], *o = READ;
int n;
int s[AC], a[AC], ans[AC], Next[AC], last[AC], r;
struct node{
int w, id;
}; struct cmp{
bool operator () (node a, node b)
{
return a.w > b.w;
}
}; priority_queue <node, vector<node>, cmp> q; inline int read()
{
int x = ; char c = getchar();
while(c > '' || c < '') c = getchar();
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x;
} void pre()
{
n = read();
for(R i = ; i <= n; i++) s[i] = read();
for(R i = ; i <= n; i++)
{
a[i] = read();
q.push((node){a[i], i});
ans[n] += a[i];
last[i] = i - ;
if(i != n) Next[i] = i + ;
}
ans[n] += s[n] * , r = n;
} void work()
{
int b = n - ;node x, now;
for(R i = b; i; i--)
{
x = q.top();
if(x.id == r)
{
q.pop();
now = q.top();
if(now.w < x.w + (s[x.id] - s[last[x.id]]) * )
{
q.pop();
Next[last[now.id]] = Next[now.id];
last[Next[now.id]] = last[now.id];
ans[i] = ans[i + ] - now.w;
q.push(x);
}
else//不然就删后者
{
Next[now.id] = ;
ans[i] = ans[i + ] - x.w - * (s[x.id] - s[last[x.id]]);
r = last[x.id];//移动末项
}
}
else//不然直接就删中间的了
{
q.pop();
Next[last[x.id]] = Next[x.id];
last[Next[x.id]] = last[x.id];
ans[i] = ans[i + ] - x.w;
}
}
for(R i = ; i <= n; i++) printf("%d\n", ans[i]);
} int main()
{
freopen("in.in", "r", stdin);
fread(READ, , , stdin);
pre();
work();
fclose(stdin);
return ;
}
P2672 推销员 优先队列 + 贪心的更多相关文章
- 洛谷P2672 推销员 题解 贪心
题目链接:https://www.luogu.org/problem/P2672 这道题目是贪心,贪心的思想是: 选择 \(m\) 户人家的最大疲劳值应该是以下两种方案中的较大值: 方案一:选择 \( ...
- 洛谷 P2672 推销员(贪心,模拟)
传送门 解题思路 第一种: 对于选i家,很显然,a值前i-1家的一定会选,所以只需要考虑最后一家的选法.要么是选择a值第i大的(就不管s了),要么选择剩下的中s最大的. 我们把每一家的情况(s和a)存 ...
- 洛谷 P2672 推销员 解题报告
P2672 推销员 题目描述 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户.螺丝街一共有N家住户,第i家住户到入口的距离为 ...
- P2672 推销员(已经补锅)
P2672 推销员 下面讲正确的贪心 题解 考虑当推销员要推销 i 家客户时,他可以有两种选择: (1)选择前 i 家疲劳值 a 最大的客户,加上这些客户里最远的距离 (2)选择前 i-1 家疲劳值 ...
- 最高的奖励 - 优先队列&贪心 / 并查集
题目地址:http://www.51cpc.com/web/problem.php?id=1587 Summarize: 优先队列&贪心: 1. 按价值最高排序,价值相同则按完成时间越晚为先: ...
- POJ2431 优先队列+贪心 - biaobiao88
以下代码可对结构体数组中的元素进行排序,也差不多算是一个小小的模板了吧 #include<iostream> #include<algorithm> using namespa ...
- hdu3438 Buy and Resell(优先队列+贪心)
Buy and Resell Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- [luoguP2672] 推销员(贪心 + 树状数组 + 优先队列)
传送门 贪心...蒟蒻证明不会... 每一次找最大的即可,找出一次最大的,数列会分为左右两边,左边用stl优先队列维护,右边用树状数组维护.. (线段树超时了....) 代码 #include < ...
- luogu P2672 推销员 |贪心
题目描述 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户.螺丝街一共有N家住户,第ii家住户到入口的距离为Si米.由于同一栋 ...
随机推荐
- Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术
第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...
- 微信小程序之注释出现的问题(.json不能注释)
js的注释一般是双斜杠// 或者是/**/这样的快注释 .json是配置文件,其内容必须符合json格式内部不允许有注释. JSON有两种数据结构: 名称/值对的集合:key : value样式: 值 ...
- 【Random】-随机数字-jmeter
参数化 Random 参数化,存储结果的变量名,名字写了,就可以给其它请求使用
- CsvHelper文档-1前言
CsvHelper文档-1前言 英文文档链接地址:CsvHelper Document 开源项目地址:CsvHelper 翻译于2018-1-5,原本可能会随时更新: 每一段代码都是经过我实际测试的, ...
- 如何在线测试Exchange的速度
最新碰到了客户需要比较国内版和国际版的Office365的速度问题,微软提供在线工具测试 这里以Exchange 测试为例子,请参考. PS Onenote贴过来只能至图片,各位看官只能将就了 这里有
- Intro to Probabilistic Model
概率论复习 概率(Probability) 频率学派(Frequentist):由大量试验得到的期望频率(致命缺陷:有些事情无法大量试验,例如一封邮件是垃圾邮件的概率,雷达探测的物体是一枚导弹的概率) ...
- HADOOP (十一).安装hbase
下载安装包并解压设置hbase环境变量配置hbase-site.xml启动hbase检测hbase启动情况测试hbase shell 下载安装包并解压 https://mirrors.tuna.tsi ...
- Keil sct分散加载文件
官方说明:http://www.keil.com/support/man/docs/armlink/armlink_pge1401393372646.htm
- c# 计算两个时间的时间差
//计算2个日期之间的天数差 DateTime dt1 = Convert.ToDateTime("2007-8-1"); DateTime dt2 = Convert.ToDat ...
- POSIX线程学习
一.什么是线程 在一个程序中的多个执行路线就叫做线程.更准确的定义是:线程是一个进程内部的一个控制序列.所有的进程都至少有一个线程.当进程执行fork调用时,将创建出该进程的一份新副本,这个新进程拥有 ...