• 【BZOJ 1150】[CTSC2007]数据备份Backup


    【链接】 我是链接,点我呀:)
    【题意】

    在这里输入题意

    【题解】

    选择的连接肯定是相邻的点对。

    那么我们处理出来长度为n-1的数组a
    其中a[i-1] = dis[i]-dis[i-1]
    那么问题就转化成在a数组中取出不相邻的k个数字。
    这k个数字的和要求最小。

    那么我们把每个数字都加入到堆中去。
    然后对于k个数字。

    每次取出堆中的最小值x
    累加答案

    但是这样做可能不是正确的。
    因为可能选择x-1,x+1这两个点比单独选择一个点来得更优一些。
    (如果你发现选x不是最优的->不选x->那么肯定吧x-1和x+1都选了更好

    因此我们得给程序一个"反悔"的机会。
    怎么给呢?
    我们可以把x-1,x+1两个点的权值和减去x的权值和->temp。
    然后加入到堆中去。
    然后把x-1,x+1这两个点删掉。
    x这个点的权值设置为刚才提到的temp
    (这里要注意的一个思想就是,把x-1,x,x+1看成是一个整体,

    这样下次如果再选这个x,就表示x不选了而把x-1,x+1选上。
    ->累加答案
    这时仍然把x看成是一个点。
    把它左边(此时是x-2)右边(x+2)的点删掉.
    然后把a[x-2]+a[x+2]-a[x]再加入到堆中
    重复上述步骤就好了
    (这个时候-a[x]其实就是把那个"整体"里面选的变成不选,不选的变成选的了
    (只有这样,x-2和x+2才能够被选中
    (而且x这个整体里面会发现选中的点的个数总是比没选中的点个数多恰好1,所以再把x-2,x+2加上,刚好只会增加一个选择的点

    我们每一次取出答案。
    其实都只会让选中的点的个数递增1
    所以堆中的每个元素其实对应的是,再多选一个点的话。
    增加的代价是多少。

    而我们每次选的都是最小的代价。
    因此贪心的策略是正确的。

    【代码】

    /**************************************************************
        Problem: 1150
        User: chengchunyang
        Language: C++
        Result: Accepted
        Time:696 ms
        Memory:5260 kb
    ****************************************************************/
     
    #include <bits/stdc++.h>
    #define ll long long
     
    using namespace std;
     
    const int N = 1e5;
    const int INF = 1e9+10;
     
    int n,k;
    int dis[N+10],a[N+10],L[N+10],R[N+10];
    priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > >pq;
    bool vis[N+10];
     
    int main()
    {
        scanf("%d%d",&n,&k);
        for (int i = 1;i <= n;i++) scanf("%d",&dis[i]);
        for (int i = 2;i <= n;i++) a[i-1] = dis[i]-dis[i-1];
        n--;
        a[0] = INF,a[n+1] = INF;
        for (int i = 0;i <= n+1;i++) L[i] = i-1,R[i] = i+1;
        for (int i = 1;i <= n;i++) pq.push(make_pair(a[i],i));
        ll ans = 0;
        for (int i = 1;i <= k;i++){
            pair<ll,int> x;
            do{
                x = pq.top();pq.pop();
            }while (vis[x.second]);
            int id = x.second;
            ans+=a[id];
            a[id] = a[L[id]]+a[R[id]]-a[id];
            pq.push(make_pair(a[id],id));
            vis[L[id]] = vis[R[id]] = 1;
            R[L[L[id]]] = id;
            L[R[R[id]]] = id;
            L[id] = L[L[id]];
            R[id] = R[R[id]];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Linux常用命令
    git常用命令查询
    专有名词
    dos2unix 转换字符
    常见脚本语言
    使用shell脚本自动化部署rabbitmp
    通过脚本来执行ssh登录
    码率mbps
    centos7 firewall指定IP与端口访问(常用)
    ubuntu16.04离线安装docker记录
  • 原文地址:https://www.cnblogs.com/AWCXV/p/8696575.html
Copyright © 2020-2023  润新知