• 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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Arduino mega 2560驱动安装失败(没有建立对验证码(TM)签名的目录的发布者信任)的解决方法
    Submile text3 安装使用技巧
    window.onload
    JS简单示例
    python类和对象的底层实现
    python类中方法加单下划线、双下划线、前后双下滑线的区别
    linux下json工具jq
    Django使用自定义的authentication登录认证
    django admin
    linux网卡桥接问题与docker网卡桥接问题
  • 原文地址:https://www.cnblogs.com/AKMer/p/10295268.html
Copyright © 2020-2023  润新知