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;
}
posted @ 2019-01-20 16:19  AKMer  阅读(134)  评论(0编辑  收藏  举报