zoukankan      html  css  js  c++  java
  • 洛谷P1792 [国家集训队]种树(链表 贪心)

    题意

    题目链接

    Sol

    最直观的做法是wqs二分+dp。然而还有一种神仙贪心做法。

    不难想到我们可以按权值从大到小依次贪心,把左右两边的打上标记,但这显然是错的比如(1 231 233 232)。我们会得到(234)而不是(463)。考虑加入一种反悔机制,也就是说我们可以增加一种决策来取消该决策的影响并加入新的决策的贡献。

    考虑这样一种做法:把原来的点权改为(231 + 232 - 233),并用双向链表维护前驱后继。把(233)的前驱改为(231)的前驱并把(233)的后继改为(232)的后继。这样我们再次选择这个点的贡献的时候就相当于选了(231 +232)

    复杂度(O(nlogn))

    // luogu-judger-enable-o2
    #include<bits/stdc++.h> 
    #define Pair pair<int, int>
    #define MP(x, y) make_pair(x, y)
    #define fi first
    #define se second
    #define LL long long 
    #define ull unsigned long long 
    #define Fin(x) {freopen(#x".in","r",stdin);}
    #define Fout(x) {freopen(#x".out","w",stdout);}
    using namespace std;
    const int MAXN = 1e6 + 10, mod = 1e9 + 7, INF = 1e9 + 10;
    const double eps = 1e-9;
    template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
    template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
    template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
    template <typename A, typename B> inline LL mul(A x, B y) {return 1ll * x * y % mod;}
    template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
    template <typename A> inline void debug(A a){cout << a << '
    ';}
    template <typename A> inline LL sqr(A x){return 1ll * x * x;}
    inline int read() {
        char c = getchar(); int x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M, a[MAXN], pre[MAXN], nxt[MAXN], vis[MAXN], cnt;
    priority_queue<Pair> q;
    signed main() {
        N = read(); M = read();
        if(M > N / 2) {puts("Error!"); return 0;}
        for(int i = 1; i <= N; i++) a[i] = read(), pre[i] = i - 1, nxt[i] = i + 1, q.push({a[i], i});
        pre[1] = N; nxt[N] = 1;
     	int ans = 0;
        while(M--) {
     		Pair p = q.top(); q.pop(); int c = p.se;
            if( vis[c]) {M++; continue;}	
     		ans += p.fi;
            a[c] = a[pre[c]] + a[nxt[c]] - a[c]; vis[pre[c]] = 1; vis[nxt[c]] = 1;
            pre[c] = pre[pre[c]]; nxt[c] = nxt[nxt[c]];
            nxt[pre[c]] = c; pre[nxt[c]] = c;
            q.push({a[c], c});
        }
        cout << ans;
        return 0;
    }
    /*
    2
    1 1
    */
    
  • 相关阅读:
    深入理解JVM(5)——垃圾收集和内存分配策略
    深入理解JVM(4)——对象的创建和访问
    深入理解JVM(3)——类加载机制
    深入理解JVM(2)——运行时数据区
    深入理解JVM(1)——栈和局部变量操作指令
    文本对比
    LRUCache
    linux服务器间文件夹拷贝
    java实现sftp客户端上传文件夹的功能
    sopUI上手教程
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10488210.html
Copyright © 2011-2022 走看看