【BZOJ】1150 [CTSC2007]数据备份Backup 堆+链表

80 篇文章 1 订阅
3 篇文章 0 订阅

题目传送门

题目大意:对给出的距离差分后的n-1个权值中挑出k个不相邻的权值,求挑出的权值的和的最小值。(看懂题目还是挺重要的)

没思路啊没思路,就算告诉我这是一道贪心题我也没思路啊,总不能是堆加链表的骚操作吧……(雾)

对于差分后的n-1个权值,我们可以全都插到堆里。先贪心的挑出一个最小值a,假设这个最小值是答案的一部分,那么显然我们不能单独再取它左边的权值b或右边的权值c了。

那么我们把它左边和右边的权值合成一个权值为b+c-a的权值,插入堆中,显然如果取了这个合成后的权值,就相当于是去了b和c的权值和。

这么搞k次就可以出答案了啊。

p.s.这题的链表需要考虑的细节比较多,望各位大佬细心些。

附上AC代码:

#include <cstdio>
#include <cctype>
#include <queue>
#define INF 0x3f3f3f3f
#define ll long long
#define pr pair<ll,int>
using namespace std;

const int N=100010;
ll n,m,x,len[N],pre,l[N],r[N],ans;
priority_queue <pr,vector<pr>,greater<pr> > que;

inline char nc(void){
	static char ch[100010],*p1=ch,*p2=ch;
	return p1==p2&&(p2=(p1=ch)+fread(ch,1,100010,stdin),p1==p2)?EOF:*p1++;
}

inline void read(ll &a){
	static char c=nc();int f=1;
	for (;!isdigit(c);c=nc()) if (c=='-') f=-1;
	for (a=0;isdigit(c);a=(a<<3)+(a<<1)+c-'0',c=nc());
	a*=f;return;
}

int main(void){
	read(n),read(m),pre=0;
	for (int i=1; i<=n; ++i) read(x),len[i]=x-pre,pre=x,l[i]=i-1,r[i]=i+1;
	for (int i=2; i<=n; ++i) que.push(make_pair(len[i],i));
	l[2]=0,r[n]=0;
	while (m--){
		while (que.top().first!=len[que.top().second]) que.pop();
		int p=que.top().second,x=l[p],y=r[p];
		ans+=len[p],que.pop();
		l[r[p]=r[y]]=p,r[l[p]=l[x]]=p;
		len[p]=x&&y?len[x]+len[y]-len[p]:INF;
		len[x]=len[y]=INF;
		que.push(make_pair(len[p],p));
	}
	printf("%lld\n",ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值