zoukankan      html  css  js  c++  java
  • Luogu 3620 数据备份(贪心反悔)

    题面

    一个不错的视频

    贪心反悔,首先读完题我们可以发现一个特别基础得贪心,就是电缆只能在相邻点之间连接,不然就是浪费了电缆长度还浪费了点,所以就把体验转化成了,n - 1个点,点权是相邻两个点的差(绝对值),我们在这些点之中选择K个点,并且要求相邻的两个点不可以都选上。

    我们想了想,简单的贪心就是用一个堆,每次只选最小的,可是非常容易hack掉,当前最优并不一定是全局最优,就比如我选择了当前最优解 i, i - 1,i + 1这些点无法选择,在选择就是 除了 i,i - 1,i + 1 这三个点之外的最优解, 但是如果选择 i - 1,i + 1 这两个点,再去选择其他点可能会更优,口胡想一下,只有这两种方案,因为加入你选了i - 1,你还想选i + x, 这里的i + x 必定是没有 i + 1这个点优秀的。

    然后我自己想反悔怎么办,比如我现在选择了i号节点,我将来有可能不选了,选他旁边的i-1 和 i + 1,考虑我们统计答案是讲所有选择的点求一个Sum, 所以想要反悔把当前这个i 削掉就行了,所以我们在插入一个a[i-1] + a[i+1] - a[i] 这么一个值,然后一直维护堆就行了。

    这就可以辣,贴个简短代码:

    #include <bits/stdc++.h>

    using namespace std;

    const int N = 1e5 + 7;
    #define INF 1e9
    /*void dfs(int u,int val){//用了u个电缆,总共价值为val
        
        if(u == k + 1){
            ans = min(ans, 1ll*val);
            return;
        }
        for(int i = 1;i <= n;++ i)
            for(int j = i + 1;j <= n;++ j)
                if(!vis[i] && !vis[j]){
                    vis[i] = vis[j] = 1;
                    val += abs(a[j] - a[i]);
                    dfs(u+1,val);
                    vis[i] = vis[j] = 0;
                }
        return;
    }
    */

    //一个贪心中的重要结论,线性走过去,如果你走过了这个点
    //那么你一定不选,因为可以先前路过的时候顺手选上,而不是现在,现在这样
    //更劣

    int s[N];
    int a[N], pre[N], nxt[N], ans;
    int n, k;
    bool vis[N];

    priority_queue <pair<int, int> > q;

    int main(){
        cin >> n >> k;
        for(int i = 1;i <= n;++ i)
            cin >> a[i];
        for(int i = 1;i < n;++ i){
            s[i] = abs(a[i+1] - a[i]);
            pre[i] = i - 1;
            nxt[i] = i + 1;
            q.push(make_pair(-s[i], i));//小根堆trick
        }
        s[0] = s[n] = INF;//这样小根堆永远不会取到最边界
        for(int i = 1;i <= k;++ i){
            while(vis[q.top().second])
            q.pop();
            int x = -q.top().first;
            int pos = q.top().second;
            q.pop();
            ans += x;
            int l = pre[pos], r = nxt[pos];//双向链表更新
            pre[pos] = pre[l], nxt[pos] = nxt[r];
            nxt[pre[pos]] = pos, pre[nxt[pos]] = pos;
            vis[l] = vis[r] = 1;
            s[pos] = s[l] + s[r] - x;
            q.push(make_pair(-s[pos], pos));
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    tcp/ip--百度百科
    Web service--百度百科
    .NET--百度百科
    ibatis--百度百科
    Struts2--百度百科
    spring--百度百科
    从头认识Spring-1.15 对SpEl的值的操作(1)-数值运算
    performSelector 方法的自己主动俘获特性
    图解WinHex使用入门
    LINQ使用与并行
  • 原文地址:https://www.cnblogs.com/Shu-Kuang/p/12846610.html
Copyright © 2011-2022 走看看