• 题解 P3620 【[APIO/CTSC 2007]数据备份】


    直接贪心(每次选最小)的话显然不对...样例都过不了... 选两个办公楼的时候,显然不能跨越另一个楼,这样不优... 于是 先把原数列处理成n-1个的数(每一个办公楼和上一个的距离),存在a[]中 题目就是 要求选出K个不相邻的数,使得选出的数的和最小

    依然考虑贪心,每次选最小的 但是若a[]是2 1 2 6,要选K=2个,先选了1,然后会发现两个2都没法选,只好选6,这样就尴尬了... 1选了就选了吧,我们考虑补救措施... 就是选1的时候,在堆里删掉两个2,然后在堆中插入2+2-1 相当于 我们以后可以取到那两个2,而且2+2-1可以表示选了两个数,因为刚才选了1,所以在这里-1

    还有个边界问题...比如取了第一个数或最后一个数,那么把a[0]和a[n]赋成极大值呗...

    因为边界的数 的两侧 只有一个有效的数,无法补救了(补救的时候需要俩数...),赋成极大值那么以后都无法取到

    那就要存储 一个数的前一个数是多少,后一个数是多少(方便删除)

    7 2 1 2 6 8 取1,删掉俩2,然后新开一个链表空间a[++n],存储2+2-1,用这个链表空间取代2 1 2

    新的链表空间,前驱是7所在位置,后继是6所在位置...不要忘了修改 7和6 的前驱和后继...

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm> 
     5 #define N 100009
     6 using namespace std;
     7 int n,dis[N],la,lheap,heap[N<<3],pos[N<<3],K,now,point[N<<3][2],prev,next;
     8 long long a[N<<3],ans;
     9 inline void push(int x)
    10 {
    11     int i=++lheap;
    12     heap[i]=x;
    13     pos[x]=i;//pos用来记录链表a[]第x个位置 在堆中的位置
    14     while (i>1)
    15         if (a[ heap[i] ]<a[ heap[i/2] ])
    16             {
    17                 swap(heap[i],heap[i/2]);
    18                 swap(pos[ heap[i] ],pos[ heap[i/2] ]);
    19                 i>>=1;
    20             }
    21         else return;
    22 }
    23 inline int del(int x)//这里删除的时候,仅仅是赋了一个极大值,塞到堆最靠下的位置啦~
    24 {
    25     int i=pos[x];
    26     a[x]=1e12;
    27     while (i*2<=lheap)
    28         {
    29             int p=i*2;
    30             if ( a[ heap[p+1] ]<a[ heap[p] ] ) p++;
    31             if ( a[ heap[p] ]<a[ heap[i] ] )
    32                 {
    33                     swap(heap[i],heap[p]);
    34                     swap(pos[ heap[i] ],pos[ heap[p] ]);
    35                     i=p;               
    36                 }
    37             else break;
    38         }
    39 }
    40 inline int pop()
    41 {
    42     int i=1,rt=heap[1];
    43     heap[1]=heap[lheap--];
    44     pos[ heap[1] ]=1;
    45     while (i*2<=lheap)
    46         {
    47             int p=i*2;
    48             if ( a[ heap[p+1] ]<a[ heap[p] ] ) p++;
    49             if ( a[ heap[p] ]<a[ heap[i] ] )
    50                 {
    51                     swap(heap[i],heap[p]);
    52                     swap(pos[ heap[i] ],pos[ heap[p] ]);
    53                     i=p;
    54                 }
    55             else return rt;
    56         }
    57     return rt;
    58 }
    59 int main()
    60 {
    61     int i,j,k;
    62     cin>>n>>K>>dis[1];
    63     a[0]=a[n]=1e12;//边界赋一个极大值...(因为a[]中是n-1个数,后边界显然是n)
    64     point[0][1]=1,point[0][0]=0,point[n][1]=n,point[n][0]=n-1;//题解中有解释...
    65     push(0),push(n);
    66     for (i=1;i<n;i++)
    67         {
    68             scanf("%d",&dis[i+1]);
    69             a[i]=dis[i+1]-dis[i];
    70             point[i][0]=i-1;
    71             point[i][1]=i+1;
    72             push(i);
    73         }
    74 
    75     for (la=n;K;K--)
    76         {
    77             ans+=a[now=pop()];//pop完了后,要先push,因为堆是在不断扩展的,pop后那个元素依然在heap
    78             prev=point[now][0],next=point[now][1]; //数组的最后一个,push后可以把它覆盖
    79             a[++la]=a[prev]+a[next]-a[now];
    80 
    81             point[la][0]=point[prev][0];
    82             point[ point[prev][0] ][1]=la;
    83             point[la][1]=point[next][1];
    84             point[ point[next][1] ][0]=la;
    85 
    86             push(la);//push要在del之前,
    87             del( prev ),del( next );
    88         }
    89     cout<<ans<<endl;
    90 }
    View Code
  • 相关阅读:
    0316-复利计算更新
    实验一 了解和掌握操作系统
    复利计划1.0
    0916 词法分析(2)
    0916词法分析
    0909 编译原理 第1次上机
    单元测试代码
    单元测试
    实验一:命令解释程序
    《构建之法》现代软件工程第1、2、3章读后感
  • 原文地址:https://www.cnblogs.com/Xchu/p/11355880.html
Copyright © 2020-2023  润新知