P3620 [APIO/CTSC 2007]数据备份[优先队列+贪心]
题目描述
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份。然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣。
已知办公楼都位于同一条街上。你决定给这些办公楼配对(两个一组)。每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份。
然而,网络电缆的费用很高。当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计 2K 个办公楼)安排备份。任一个办公楼都属于唯一的配对组(换句话说,这 2K 个办公楼一定是相异的)。
此外,电信公司需按网络电缆的长度(公里数)收费。因而,你需要选择这 K对办公楼使得电缆的总长度尽可能短。换句话说,你需要选择这 K 对办公楼,使得每一对办公楼之间的距离之和(总距离)尽可能小。
下面给出一个示例,假定你有 5 个客户,其办公楼都在一条街上,如下图所示。这 5 个办公楼分别位于距离大街起点 1km, 3km, 4km, 6km 和 12km 处。电信公司仅为你提供 K=2 条电缆。

上例中最好的配对方案是将第 1 个和第 2 个办公楼相连,第 3 个和第 4 个办公楼相连。这样可按要求使用 K=2 条电缆。第 1 条电缆的长度是 3km―1km = 2km,第 2 条电缆的长度是 6km―4km = 2 km。这种配对方案需要总长 4km 的网络电缆,满足距离之和最小的要求。
<br/ >
解析
首先,容易想到最优解一定只能是相邻的办公楼两两连接构成的。理由很简单,任意的跨过某些办公楼连接的电缆一定不如只连接其跨过的任意两个相邻电缆。
那么,我们就只用分析如何处理相邻的两两办公楼之间连接电缆的问题,对于两两办公楼之间的距离,我们将其编号为\(1\sim n-1\)。
我到这里是先想到一个dp,结果一看数据范围直接懵逼,\(O(n^2)\)用脚趾头想都是过不了的。然后想了想似乎网络流也能做,不过复杂度貌似也过不去。。。
老夫掐指一算,(根据lyd的书)有了如下分析:
对于任意一对(相邻两个)办公楼\(i,j\),局部最优解只会有两种情况:
- 连接\(i,j\)。
- 连接\(i-1,i\)和\(j,j+1\)。
显而易见,1情况最优时\(i-1,i\)和\(j,j+1\)是不能选的。对于2情况,由于所有距离都是正数,故选择\(i-1,i\)和\(j,j+1\)两段一定比只选其中某一段更优。
但是我们发现如果直接贪心,也就是每次选择最小距离累加进答案,是有后效性的,因为这会导致最小距离两侧的距离不可选择,但最优解仍然有可能包含它们两个。
注意到此处直接贪心的后效性产生的原因仅仅是因为其影响了当前状态下最短距离两侧的距离的选择,既然如此,那我们不妨考虑一个可以反悔并消除之前选择的影响的贪心。
那么我们可以得到一种贪心:建立链表\(1\sim n-1\),对应所有距离,并映射到一个优先队列中。每次贪心选择最短距离\(k_d\)累加进答案,假设其所在位置为\(d\),把\(d-1,d+1\)两段打上标记,表示不能选择,再在链表中删除\(d-1,d,d+1\)的节点,在堆中也删除对应的节点,再在链表原来的位置加入新节点,其权值为\(k_{d-1}+k_{d+1}-k_{d}\)(k为距离大小),同时也在堆中新增一个权值为\(k_{d-1}+k_{d+1}-k_{d}\)的节点。这样一来,当我们在之后的状态中再次选择新节点时,就会消除之前选择\(d\)的影响,相当于选择了\(d-1,d+1\)而不选\(d\)。
下图中,黑色填充表示选择该段。
第一次选择位置\(d\)的点时,答案\(ans=\cdots+k_d\)。

第二次选择该位置的点,答案\(ans=\cdots +k_d+k_{d-1}+k_{d+1}-k_{d}=\cdots+k_{d-1}+k_{d+1}\)

我们删除原节点并新增节点的操作实际上相当于对一个子问题做出了决策,并逐步解决规模更大的子问题。
下图中如果红框内表示当前状态的最优解,实际上他就是该子问题的最优解,在之后的决策中,我们可以直接使用这个子问题的最优解,而不用考虑其内部是如何构成的。

我们需要证明更一般的情况以解决整个问题,下面我们证明全局最优解也满足这个性质。
首先,显然我们的贪心具有决策包容性,任意的子问题一定包含了比它更小的所有子问题(这是一个区间上的问题)。
我们不妨使用微扰法和范围缩放法进行贪心正确性的证明。
尝试证明标记不可选择区域的操作的正确性,假设当前子问题状态如下:

即,前一步时,子问题最优解为黑色区域,当前最短距离为灰色区域。如果此时我们选择了灰色区域,那么一定有所有距离\(>\)最右边的那段灰色距离,且已经选择的所有黑色区域的任意一个的距离\(<\)灰色区域的距离,因此在这个子问题中我们一旦选择了灰色区域,一定会减少一个比灰色区域更小的距离,增加一个比灰色区域更大的距离到答案中,这一定不是最优解。
显然这个性质可以扩展到任意子问题,即任意时刻做出如上贪心决策不会使得结果变差。
此外,我们还要注意一些细节:链表的上下界处理,我们要保证表头和表尾不被选择(它们不包含在任一子问题中),只需把初值赋为无穷大即可。
其它差不多的题:P1484 种树 P1792 [国家集训队]种树
参考代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 500010
#define ll long long
#define INF 0x7fffffff
using namespace std;
inline ll read()
{
int f=1,x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
struct node{
ll val;
int id;
bool operator<(const node &a)const{
return val>a.val;
}
node(){}
node(int _id,ll _val){id=_id,val=_val;}
};
ll a[N],n,k,sum[N];
bool v[N];
priority_queue<node> q;
struct link{
ll val;
int pre,next;
}g[N];
int main()
{
n=read(),k=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<n;++i){
g[i].pre=i-1,g[i].next=i+1;
sum[i]=a[i+1]-a[i];
g[i].val=sum[i];
q.push(node(i,sum[i]));
}
g[n].val=g[0].val=INF;
ll ans=0;
for(int i=1;i<=k;++i){
while(v[q.top().id]) q.pop();
node x=q.top();q.pop();ans+=g[x.id].val;
g[x.id].val=g[g[x.id].next].val+g[g[x.id].pre].val-g[x.id].val;
v[g[x.id].next]=v[g[x.id].pre]=1;
q.push(node(x.id,g[x.id].val));
g[x.id].next=g[g[x.id].next].next;
g[x.id].pre=g[g[x.id].pre].pre;
g[g[x.id].pre].next=x.id;
g[g[x.id].next].pre=x.id;
}
printf("%lld\n",ans);
return 0;
}
P3620 [APIO/CTSC 2007]数据备份[优先队列+贪心]的更多相关文章
- 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)
洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...
- 洛谷 P3620 [APIO/CTSC 2007]数据备份 解题报告
P3620 [APIO/CTSC 2007]数据备份 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同 ...
- P3620 [APIO/CTSC 2007]数据备份
P3620 [APIO/CTSC 2007]数据备份 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同 ...
- 洛谷P3620 [APIO/CTSC 2007] 数据备份 [堆,贪心,差分]
题目传送门 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽 ...
- [luogu3620][APIO/CTSC 2007]数据备份【贪心+堆+链表】
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...
- [APIO/CTSC 2007]数据备份(贪心+堆)
你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣. ...
- 洛谷$P3620\ [APIO/CTSC 2007]$数据备份 贪心
正解:贪心 解题报告: 传送门$QwQ$ $umm$感觉这种问题还蛮经典的,,,就选了某个就不能选另一个这样儿,就可以用堆模拟反悔操作 举个$eg$,如果提出了$a_i$,那就$a_{i-1}$和$a ...
- 洛谷P3620 [APIO/CTSC 2007] 数据备份
题目 贪心+堆. 一般贪心题用到堆的时候都会存在一种反悔操作,因此这个题也不例外. 首先电缆一定是连接两个相邻的点的,这很好证明,其次一个点只能被一条电缆连接,所以我们通过选这个电缆,不选相邻电缆和选 ...
- luogu P3620 [APIO/CTSC 2007]数据备份
luogu 首先如果一条线不是了连接的相邻两个位置一定不优,把它拆成若干连接相邻位置的线.所以现在问题是有\(n\)个物品,选\(k\)个,要求选的位置不能相邻,求最小总和 如果没有选的位置不能相邻这 ...
随机推荐
- Python3 列表list合并的4种方法
方法1: 直接使用"+"号合并列表 aList = [1,2,3] bList = ['www', 'pythontab.com'] cList = aList + bList ...
- python断点
pycharm怎么debug单步调试 1.打开一个Pycharm的界面,需要选中编辑器中的左侧. 2.点击Run---->Debug运行 3.点击箭头,向下运行 4.可以看到代码运行到下一条 5 ...
- lay-verify
lay-verify:是表单验证的关键字 required (必填项) phone(手机号) email(邮箱) url(网址) number(数字) date(日期) identity(身份证) 自 ...
- json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (ch
阐述 想要把一个字符串转化成字典对象,在使用json的过程出现如此报错 解决方法 将字符串里面的单引号改为双引号
- Linux 中的 ~/. 表示的意思
在Linux中, ~ 表示用户的目录, 如用户名是Gavin, 那么~/表示 /home/Gavin 所以~/. 表示 用户目录下的隐藏文件. 扩展: 若以用户身份登录 ~ 表示 /home 目录 ...
- 路由Routers
路由Routers 对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息. REST framework提供 ...
- ES6之reduce和reduceRight方法应用实例
for循环是最基本的遍历循环,但是有些时候并不是很实用,且效率和性能较低,故本文列举出工作学习中碰到的reduce方法应用实例,供自己揣摩熟练应用,以提高自己的研发水平和研发效率. reduce方法( ...
- Microsoft Visual Studio常用快捷键
快速补全关键字 1)tab; 删除整行代码 1)Ctrl + L; 回到上一个光标位置/前进到下一个光标位置 1)回到上一个光标位置:使用组合键“Ctrl + -”; 2)前进到下一个光标位置:“Ct ...
- 【洛谷 P4302】 [SCOI2003]字符串折叠(DP)
题目链接 简单区间dp 令\(f[i][j]\)表示\([i,j]\)的最短长度 先枚举区间,然后在区间中枚举长度\(k\),看这个区间能不能折叠成几个长度为\(k\)的,如果能就更新答案. #inc ...
- 浅谈对BFC的认识,以及用bfc解决浮动问题
我们在前端的学习过程中常常会遇到BFC,用BFC来解决一些margin塌陷.margin合并清理浮动流的问题 那么问题来了,我们所说的BFC到底是个什么东西呢: 什么是BFC BFC(Block Fo ...