BZOJ 1150 [CTSC2007]数据备份Backup(贪心+优先队列)

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1150

【题目大意】

  给出n个数,请你挑出k对(每个数不可重复选取),使得他们差的绝对值之和最小(k小于等于n/2)

【题解】

  因为数列给出有序,省去排序步骤,我们发现最优答案一定是选择k对相邻的数,
  因此我们将相邻的数两两之间求差,得到差分数列,
  现在问题转化为在这个新的数列中,选取k个不相邻的数,使得和最小。
  我们发现在选取一个数之后,只对左右两边的数有影响,
  所以,每当我们选取一个数,就把这个数以及它两边的数删除,
  然后再在它的位置上新加一个数,值为被选取的数两边数的和减去被选去的数
  那么我们如果选了这个数,就相当于原来的数我们就不选了,类似于最大流的退流思想。
  这样做之后,我们每次只要选择最小的数,累加到答案即可。
  对于被删除了却仍然在优先队列中的数,我们用一个标记来维护它。

【代码】

#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;
const int N=200010;
unsigned long long ans;
bool del[N];
struct data{
    int id,key,l,r;
    bool operator <(const data&rhs)const{
       return key>rhs.key;
    }
}w[N];
priority_queue<data> Q;
int a[N],n,k;
int main(){
    while(~scanf("%d%d",&n,&k)){
        ans=0;
        memset(del,0,sizeof(del));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<n;i++){
            w[i].id=i;
            w[i].key=a[i+1]-a[i];
            w[i].l=i-1;
            w[i].r=i+1;
            Q.push(w[i]);
        }n--;
        w[n].r=w[0].l=w[0].r=0;
        w[0].key=0x3f3f3f3f;
        while(k--){
            for(;;){
                data t=Q.top();
                Q.pop();
                int id=t.id,l=w[id].l,r=w[id].r;
                if(del[id])continue;
                del[id]=del[l]=del[r]=1;
                ans+=w[id].key;
                w[++n].id=n;
                w[n].key=w[l].key+w[r].key-w[id].key;
                w[n].l=w[l].l; w[n].r=w[r].r;
                w[w[l].l].r=n; w[w[r].r].l=n;
                Q.push(w[n]);
                break;
            }
        }printf("%lld\n",ans);
    }return 0;
}
时间: 2024-10-22 07:25:41

BZOJ 1150 [CTSC2007]数据备份Backup(贪心+优先队列)的相关文章

【链表】bzoj 1150: [CTSC2007]数据备份Backup

1150: [CTSC2007]数据备份Backup Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1136  Solved: 458[Submit][Status][Discuss] Description Input 输入的第一行包含整数n和k,其中n(2 ≤ n ≤100 000)表示办公楼的数目,k(1≤ k≤ n/2)表示可利用的网络电缆的数目.接下来的n行每行仅包含一个整数(0≤ s ≤1000 000 000), 表示每个办公楼到大

bzoj 1150: [CTSC2007]数据备份Backup

Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一

BZOJ 1150 CTSC2007 数据备份Backup 堆+贪心

题目大意:给定一个长度为n?1的序列,要求选出k个不相邻的数使得和最小 费用流显然能跑,而且显然过不去- - 考虑用堆模拟费用流 一个错误的贪心是每次取最小,这样显然过不去样例 我们把[每次取最小]改为[每次选择一个区间取反],用堆来维护这些区间即可 每次取出最小的区间,然后将两边合并 (比如现在堆里有[1,3][4,4][5,5])这三个区间,我取走了[4,4]并计入答案,那么我删除[1,3]和[5,5]这两个区间,并加入[1,5]这个区间,权值为[1,3]的权值+[5,5]的权值-[4,4]

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

参考:http://blog.csdn.net/Regina8023/article/details/44158947 神奇的做法.题意相当于若干个数取不相邻的k个使最小.先把数组差分,len表示这段空的长度.设二元组(i,len[i]),开一个小根堆把二元组塞进去,以len排序.每次取出一个二元组,因为单纯的贪心是不行的,所以设计一个"反悔"操作.记录二元组的前驱pr后继ne,把拿出来的二元组的len加进答案,然后把当前二元组和它的前驱后继当成一个,也就是len[x]=len[pr[

【BZOJ 1150】 1150: [CTSC2007]数据备份Backup (贪心+优先队列)

1150: [CTSC2007]数据备份Backup Description 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅

1150: [CTSC2007]数据备份Backup

1150: [CTSC2007]数据备份Backup https://lydsy.com/JudgeOnline/problem.php?id=1150 分析: 堆+贪心. 每次选最小的并一定是最优的,如果不选这个最小的,那一定是为了取它左右两边(两条都要取才可能比当前优). 如果先选了最小的,考虑后面如何撤销.选了这个后,左右两边的线段就要删了,那么在加入一个长度为:左边的长度+右边的长度-当前的线段的长度 的一条线段. wqs二分,模拟费用流 代码: 1 #include<cstdio>

【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆

题目描述 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于唯一的配

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

题目 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于唯一

bzoj1150: [CTSC2007]数据备份Backup--贪心+优先队列维护堆

题目大意:将k对点两两相连,求最小长度 易证得,最优方案中,相连的办公楼一定是取相邻的比取不相邻的要更优 然后就可以用贪心来做这道题了.. 之前向CZL大神学习了用堆来贪心的做法orz 大概思路就是将初始所有的线段放进堆里 每次取最短的线段进行连接,且ans+=a[i] 取完后删除当前线段,与相邻的两条线段,同时再插入新边,权值为a[pre]+a[next]-a[now] 其作用与最大流中的反向弧有点像,下一次若取到这条边,即ans+=a[pre]+a[next]-a[now] 很明显a[now