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

来源:互联网 发布:淘宝网大码女装夏装 编辑:程序博客网 时间:2024/06/03 05:40

题目传送门

题目大意:对给出的距离差分后的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;}

原创粉丝点击