BZOJ1150:[CTSC2007]数据备份
浅谈堆:https://www.cnblogs.com/AKMer/p/10284629.html
题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=1150
显然,这题用贪心转化一下题意就是给你\(n-1\)个数,选\(k\)个不相邻的数权值和最小。
假设最小值是\(a_x\),那么选完\(a_x\)之后\(a_{x-1}\)和\(a_{x+1}\)就不能选了。
如果\(a_{x-1}\)和\(a_{x+1}\)只选了某一个,显然把这个换成\(a_x\)更优。
所以最优解要么有\(a_x\)没有\(a_{x-1}\)和\(a_{x+1}\),要么同时有\(a_{x-1}\)和\(a_{x+1}\)。
所以我们每次从堆里取出来一个数之后,再把它前一个数和后一个数在堆里删掉,往堆里塞一个\(a_{i-1}+a_{i+1}-a_i\)即可。这样就可以考虑这两种情况了。
如果取出的这个数前面没有数或者后面没有数,那么就不需要加\(a_{i-1}+a{i+1}-a_i\)进堆,而是把它后一个数或者前一个数也从堆里删掉。可以证明,如果选了当前这个数,那么与它相邻的那个数必然不会被选。因为选与它相邻的数之后所遇到的局面,选当前数也能到达,这个决策包涵了选相邻的数的决策,而且选当前数更优,所以与当前数相邻的那个数可以直接舍弃了。
时间复杂度:\(O((n+k)logn)\)
空间复杂度:\(O(n)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+5;
int n,m,ans;
int a[maxn];
int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}
struct Linked_List {
	int lst,nxt,val,in_heap;
	Linked_List() {}
	Linked_List(int _lst,int _nxt,int _val) {
		lst=_lst,nxt=_nxt,val=_val;
	}
}L[maxn];
struct Heap {
	int tot;
	int tree[maxn];
	bool less(int id1,int id2) {return L[id1].val<L[id2].val;}
	void up(int pos) {
		while(pos>1) {
			if(less(tree[pos],tree[pos>>1])) {
				swap(tree[pos],tree[pos>>1]);
				swap(L[tree[pos]].in_heap,L[tree[pos>>1]].in_heap);
				pos>>=1;
			}
			else break;
		}
	}
	void down(int pos) {
		int son=pos<<1;
		while(son<=tot) {
			if(son<tot&&less(tree[son|1],tree[son]))son|=1;
			if(less(tree[son],tree[pos])) {
				swap(tree[son],tree[pos]);
				swap(L[tree[son]].in_heap,L[tree[pos]].in_heap);
				pos=son,son=pos<<1;
			}
			else break;
		}
	}
	void ins(int v) {tree[++tot]=v,L[v].in_heap=tot,up(tot);}
	int pop() {
		int res=tree[1];
		tree[1]=tree[tot--];
		L[tree[1]].in_heap=1;
		down(1);return res;
	}
	void del(int id) {
		if(id==tot) {tot--;return;}
		tree[id]=tree[tot--];
		L[tree[id]].in_heap=id;
		if(id==1)down(id);
		else if(id==tot)up(id);
		else up(id),down(id);
	}
}T;
int main() {
	n=read(),m=read();
	for(int i=1;i<=n;i++) {
		a[i]=read();
		if(i>1) {
			L[i-1]=Linked_List(i-2,i,a[i]-a[i-1]);
			T.ins(i-1);
		}
	}
	while(m--) {
		int id=T.pop(),lst=L[id].lst,nxt=L[id].nxt;
		ans+=L[id].val;
		if(!lst) {
			T.del(L[nxt].in_heap);
			L[L[nxt].nxt].lst=0;continue;
		}
		if(nxt==n) {
			T.del(L[lst].in_heap);
			L[L[lst].lst].nxt=n;continue;
		}
		T.del(L[lst].in_heap),T.del(L[nxt].in_heap);
		L[lst].val=L[lst].val+L[nxt].val-L[id].val;T.ins(lst);
		L[lst].nxt=L[nxt].nxt,L[L[nxt].nxt].lst=lst;
	}
	printf("%d\n",ans);
	return 0;
}
												
											BZOJ1150:[CTSC2007]数据备份的更多相关文章
- BZOJ1150 [CTSC2007]数据备份Backup 链表+小根堆
		
BZOJ1150 [CTSC2007]数据备份Backup 题意: 给定一个长度为\(n\)的数组,要求选\(k\)个数且两两不相邻,问最小值是多少 题解: 做一个小根堆,把所有值放进去,当选择一个值 ...
 - bzoj1150 [CTSC2007]数据备份Backup 双向链表+堆
		
[CTSC2007]数据备份Backup Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2727 Solved: 1099[Submit][Stat ...
 - BZOJ1150[CTSC2007]数据备份Backup——模拟费用流+堆+链表
		
题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游 ...
 - bzoj1150 [CTSC2007]数据备份
		
Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中 ...
 - BZOJ1150 [CTSC2007]数据备份Backup  【堆 + 链表】
		
题目 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的 ...
 - BZOJ1150 [CTSC2007] 数据备份Backup 贪心_堆_神题
		
Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家 ...
 - BZOJ1150 [CTSC2007]数据备份Backup  贪心  堆
		
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1150 题意概括 数轴上面有一堆数字. 取出两个数字的代价是他们的距离. 现在要取出k对数,(一个数 ...
 - bzoj1150: [CTSC2007]数据备份Backup--贪心+优先队列维护堆
		
题目大意:将k对点两两相连,求最小长度 易证得,最优方案中,相连的办公楼一定是取相邻的比取不相邻的要更优 然后就可以用贪心来做这道题了.. 之前向CZL大神学习了用堆来贪心的做法orz 大概思路就是将 ...
 - bzoj1150: [CTSC2007]数据备份Backup
		
题目大意: 在n个点中,选出k对相邻的互不相同的点,使k段距离的总和最小. 贪心,双向链表. 首先,点之间的距离是动态的,所以要用堆来维护. 每次都选择最近的点.但因为其他情况,可能最终不会选择这 ...
 - 【BZOJ1150】[CTSC2007]数据备份Backup 双向链表+堆(模拟费用流)
		
[BZOJ1150][CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此 ...
 
随机推荐
- Vue学习-基础语法
			
Vue v-if指令 Vue.js的指令是以v-开头的,它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTM ...
 - SpringMVC的第一个入门案例
			
用户提交一个请求,服务器端处理器在接收到这个请求后,给出一条欢迎信息,在页面中显示. 第一步:导入jar包 在原有Springjar包基础上添加2个jar包 spring-webmvc-4.2.0.R ...
 - 教你管理SQL数据库系列(1-4)
			
原文 教你管理 SQL Server 数据库(1)数据库的结构 http://bbs.51cto.com/thread-1084951-1.html教你管理 SQL Server 数据库(2)系统数 ...
 - Symfony 使用KnpTimeBundle
			
使用time_diff时出现:diff.ago.hour; 解决:1:引入"knplabs/knp-time-bundle": "^1.7",https://g ...
 - WORD表格数据运算技巧
			
我们经常会用WORD制作表格,有时表内的数据要运算的,WORD表格数据运算能力无法与EXCEL相比.但常见的乘除加减.相邻数据累加,将金额数字自动转成大写,WORD都能在表格内自动完成.下面以一个简单 ...
 - setTimeout解决循环值的几种方法
			
for(var i=0;i<5;i++){ setTimeout(function(){ console.log(`错误 ${i}`); },0) } for(var i=0;i<5;i+ ...
 - LeetCode:范围求和||【598】
			
LeetCode:范围求和||[598] 题目描述 给定一个初始元素全部为 0,大小为 m*n 的矩阵 M 以及在 M 上的一系列更新操作. 操作用二维数组表示,其中的每个操作用一个含有两个正整数 a ...
 - Python:笔记(2)——函数与模块
			
Python:笔记(2)——函数与模块 Python函数 关于函数 1.我们可以使用Help来查看函数的帮助信息 2.调用函数的时候,如果传入的参数数量或者类型不符合均会报错. 3.函数名其实就是一个 ...
 - mathjax
			
MathJax.Hub.Typeset() method. This will cause the preprocessors (if any were loaded) to run over the ...
 - python 3 递归调用与二分法
			
递归调用与二分法 1.递归调用 递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身. 示例: def age(n): if n == 1: return 18 # 结束条件 return a ...