题目传送门

  

题目描述

你在一家 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 的网络电缆,满足距离之和最小的要求。

输入输出格式

输入格式:

输入文件的第一行包含整数 n 和 k,其中 n(1≤n≤100 000)表示办公楼的数目,k(1≤k≤n/2)表示可利用的网络电缆的数目。

接下来的 n 行每行仅包含一个整数(0≤s≤1000 000 000), 表示每个办公楼到大街起点处的距离。这些整数将按照从小到大的顺序依次出现。

输出格式:

输出文件应当由一个正整数组成,给出将 2K 个相异的办公楼连成 K 对所需的网络电缆的最小总长度。

输入输出样例

输入样例#1: 复制

5 2
1
3
4
6
12
输出样例#1: 复制

4

说明

30%的输入数据满足 n≤20。

60%的输入数据满足 n≤10 000


  分析:易证,最优解中配对的大楼一定是相邻的,就可以将每两栋相邻的大楼之间的距离Di求出来,就可以将问题转化为:[有n-1个元素的数列Di,从中取出k个数,使得这k个数的和最小,并且相邻的数不能同时选]。

  再从简单的情况开始分析:

  如果k=1,那么直接选最小的元素。

  如果k=2,那么要么选最小的元素D[i]和除了D[i-1],D[i],D[i+1]以外的最小的元素,要么选择D[i]两边的元素即D[i-1]和D[i+1]

  那么由第二种情况就可以分析得到,对于当前数列中的元素,要么一定要选最小元素D[i],要么就一定要选最小元素两边的元素D[i-1],D[i+1]。也就是说,最小元素左右两侧的元素要么同时被选,要么同时不选。。那么就可以先选出D[]中最小的元素D[i],然后将D[i-1],D[i],D[i+1]从数列中删除,并在原位置插入一个新元素D[i-1]+D[i+1]-D[i],然后重复操作即可。(因为如果在后面的操作中选择了D[i-1]+D[i+1]-D[i]这个元素,就相当于去掉已选择的结果中的D[i]换上D[i-1]+D[i+1],如果后面没选该元素,则选择D[i]是一步最优策略)

  那算法也就可以推导出了:建立一个链表L和一个小根堆H,L中有n-1个元素,每个元素与小根堆中的每一个元素成一一映射关系,它们的元素都是D[i],也就是每两栋楼之间的距离。取出堆顶,将权值累加到答案上,再将堆顶x删除,同时将x的左右两侧的元素pre[x],nxt[x]删除,在同样的位置插入一个新元素p,p的权值D[p]=D[pre[x]]+D[nxt[x]]-D[x],再在链表的对应位置中插入对应的节点p。重复k次即可。

  不过实际操作的时候有很多细节要注意,具体细节看代码吧。

  Code:

  

#include<bits/stdc++.h>
#define Fi(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=2e5+;
int n,k,size,heap[N],fheap[N];
int num[N],nxt[N],pre[N],ans;
inline int read()
{
char ch=getchar();int num=;bool flag=false;
while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
return flag?-num:num;
}
inline void delet(int x)
{
heap[x]=heap[size--];
fheap[heap[size+]]=x;
int ka=x;
if(num[heap[ka]]>=num[heap[ka>>]]){
int s=ka<<;
while(s<=size){
if(s<size&&num[heap[s+]]<num[heap[s]])s++;
if(num[heap[ka]]>num[heap[s]]){
swap(fheap[heap[ka]],fheap[heap[s]]);
swap(heap[ka],heap[s]);ka=s;s=ka<<;}
else break;}}
else{while(ka>){if(num[heap[ka]]<num[heap[ka>>]]){
swap(fheap[heap[ka]],fheap[heap[ka>>]]);
swap(heap[ka],heap[ka>>]);ka>>=;}
else break;}}
}
inline void insert(int x)
{
heap[++size]=x;fheap[x]=size;int ka=size;
while(ka>){
if(num[heap[ka]]<num[heap[ka>>]])
{swap(fheap[heap[ka]],fheap[heap[ka>>]]);
swap(heap[ka],heap[ka>>]);ka>>=;}
else break;}
}
int main()
{
n=read();k=read();int x1,x2;
x1=read();Fi(i,,n){
nxt[i]=i+;pre[i]=i-;x2=read();
num[i]=x2-x1;x1=x2;insert(i);}
num[]=1e9+;num[++n]=1e9+;
insert(),insert(n);
Fi(i,,k){
int x=heap[];delet();
delet(fheap[pre[x]]);delet(fheap[nxt[x]]);
int x1=num[pre[x]],x2=num[nxt[x]];
num[++n]=x1+x2-num[x];
pre[n]=pre[pre[x]];nxt[n]=nxt[nxt[x]];
pre[nxt[n]]=n;nxt[pre[n]]=n;insert(n);
ans+=num[x];}cout<<ans;return ;
}

洛谷P3620 [APIO/CTSC 2007] 数据备份 [堆,贪心,差分]的更多相关文章

  1. 洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)

    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/132 ...

  2. 洛谷 P3620 [APIO/CTSC 2007]数据备份 解题报告

    P3620 [APIO/CTSC 2007]数据备份 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同 ...

  3. 洛谷P3620 [APIO/CTSC 2007] 数据备份

    题目 贪心+堆. 一般贪心题用到堆的时候都会存在一种反悔操作,因此这个题也不例外. 首先电缆一定是连接两个相邻的点的,这很好证明,其次一个点只能被一条电缆连接,所以我们通过选这个电缆,不选相邻电缆和选 ...

  4. 洛谷$P3620\ [APIO/CTSC 2007]$数据备份 贪心

    正解:贪心 解题报告: 传送门$QwQ$ $umm$感觉这种问题还蛮经典的,,,就选了某个就不能选另一个这样儿,就可以用堆模拟反悔操作 举个$eg$,如果提出了$a_i$,那就$a_{i-1}$和$a ...

  5. P3620 [APIO/CTSC 2007]数据备份[优先队列+贪心]

    题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...

  6. P3620 [APIO/CTSC 2007]数据备份

    P3620 [APIO/CTSC 2007]数据备份 题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同 ...

  7. [luogu3620][APIO/CTSC 2007]数据备份【贪心+堆+链表】

    题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏 ...

  8. [APIO/CTSC 2007]数据备份(贪心+堆)

    你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣. ...

  9. luogu P3620 [APIO/CTSC 2007]数据备份

    luogu 首先如果一条线不是了连接的相邻两个位置一定不优,把它拆成若干连接相邻位置的线.所以现在问题是有\(n\)个物品,选\(k\)个,要求选的位置不能相邻,求最小总和 如果没有选的位置不能相邻这 ...

随机推荐

  1. #应用openxml读写excel代码

    这个例子比较简单,没有考虑格式之类的问题. using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadshe ...

  2. js和jq实现全选反选

    在前端中用到全选反选的案例并不少,在这里呢我就实现这个功能给大家参考参考. 这里呢就先贴上我的html和css代码 <div class="wrap"> <tab ...

  3. 51Nod 1062 序列中最大的数 | 简单DP

    #include "iostream" #include "cstdio" using namespace std; #define LL long long ...

  4. LightOJ 1306 - Solutions to an Equation 裸EXGCD

    本题是极其裸的EXGCD AX+BY+C=0 给你a b c 和x与y的区间范围,问你整数解有几组 作为EXGCD入门,题目比较简单 主要需要考虑区间范围的向上.向下取整,及正负符号的问题 问题是这正 ...

  5. 【HNOI】矩阵染色 数论

    [题目描述]一个2*i的矩阵,一共有m种颜色,相邻两个格子颜色不能相同,m种颜色不必都用上,f[i]表示这个答案,求Σf[i]*(2*i)^m (1<=i<=n)%p. [数据范围] 20 ...

  6. Android使用TextView实现跑马灯效果(自定义控件)

    对于一个长的TetxView 折行显示是一个很好的办法,另一种方法就是跑马灯显示(单行滚动) 1.折行显示的长TextView <LinearLayout xmlns:android=" ...

  7. python—RE正则表达式

    re正则表达式 正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C 编写的 ...

  8. python设计模式之单例模式(一)

    单例设计模式的概念: 单例设计模式即确保类有且只有一个特定类型的对象,并提供全局访问点.一般我们操作数据库的时候为了避免统一资源产生互相冲突,创建单例模式可以维护数据的唯一性. 单例模式的特性: 确保 ...

  9. SQL利用Case When Then多条件判断SQL 语句

    http://www.cnblogs.com/kevin2013/archive/2010/07/02/1769682.html SQL利用Case When Then多条件判断SQL ,用于sele ...

  10. jQuery 中的 unbind() 方法

    jQuery 中的 unbind() 方法是 bind() 方法的反向操作,从每一个匹配的元素中删除绑定的事件. 语法结构: unbind([type][, data]); type是事件类型,dat ...