zoukankan      html  css  js  c++  java
  • 「NOI2019」序列

    有趣的一道题

    首先考虑费用流建图,大概长这样:

    (其余边流量均为1,源点至多流出K单位流量)

    然后我们有一个显然的发现:一个点与源点或汇点的连边一旦被选了,就不会退掉

    于是我们得出一个结论:一个数只要被选就不可能将它删除

    我们抛开费用流,考虑这样一个算法:

    我们每次上下各选一个点,在零散点对数量不超过(K-L)的前提下权值和最大,这本质也是费用流过程,但具体的流量什么的可以忽略

    于是我们贪心地考虑几种情况即可,用堆维护

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 200005;
    int n, K, L, t, i, j, a[N], b[N], f[N], tot;
    long long ans = 0;
    struct str {
        int a, x;
    };
    bool operator<(str a, str b) {
        if (a.a == b.a)
            return a.x < b.x;
        return a.a < b.a;
    }
    struct PR {
        priority_queue<str> q, del;
        void Del() {
            while (!del.empty() && q.top().a == del.top().a && q.top().x == del.top().x) del.pop(), q.pop();
        }
        void Push(str x) {
            q.push(x);
            Del();
        }
        void Erase(str x) {
            del.push(x);
            Del();
        }
        str Top() {
            Del();
            return q.top();
        }
        bool Empty() {
            Del();
            return q.empty();
        }
        void Pop() {
            Del();
            q.pop();
        }
        void Clear() {
            while (!q.empty()) q.pop();
            while (!del.empty()) del.pop();
        }
    } q1, q2, q3, q4, q5;
    void cha(str x) {
        if (f[x.x] == 2)
            q4.Erase((str){ a[x.x], x.x });
        else {
            q1.Erase((str){ a[x.x] + b[x.x], x.x });
            q5.Push((str){ b[x.x], x.x });
        }
        q2.Erase(x);
    }
    void chb(str x) {
        if (f[x.x] == 1)
            q5.Erase((str){ b[x.x], x.x });
        else {
            q1.Erase((str){ a[x.x] + b[x.x], x.x });
            q4.Push((str){ a[x.x], x.x });
        }
        q3.Erase(x);
    }
    int main() {
        freopen("sequence.in", "r", stdin);
        freopen("sequence.out", "w", stdout);
        scanf("%d", &t);
        while (t--) {
            scanf("%d %d %d", &n, &K, &L);
            for (i = 1; i <= n; ++i) {
                scanf("%d", &a[i]);
                f[i] = 0;
            }
            q1.Clear(), q2.Clear(), q3.Clear(), q4.Clear(), q5.Clear();
            for (i = 1; i <= n; ++i) scanf("%d", &b[i]);
            for (i = 1; i <= n; ++i) {
                q1.Push((str){ a[i] + b[i], i });
                q2.Push((str){ a[i], i });
                q3.Push((str){ b[i], i });
            }
            tot = K - L;
            ans = 0;
            while (K--) {
                if (tot) {
                    --tot;
                    str x = q2.Top();
                    str y = q3.Top();
                    ans += x.a + y.a;
                    if (f[x.x] == 2)
                        ++tot;
                    if (f[y.x] == 1)
                        ++tot;
                    if (x.x == y.x)
                        ++tot;
                    cha(x);
                    f[x.x] |= 1;
                    chb(y);
                    f[y.x] |= 2;
                } else {
                    str x = (str){ -1000000000, 0 };
                    if (!q4.Empty())
                        x = q4.Top();
                    str y = (str){ -1000000000, 0 };
                    if (!q5.Empty())
                        y = q5.Top();
                    str A = q2.Top();
                    str B = q3.Top();
                    str c = q1.Top();
                    if (c.a > A.a + y.a && c.a > B.a + x.a) {
                        ans += c.a;
                        q1.Pop();
                        q2.Erase((str){ a[c.x], c.x });
                        q3.Erase((str){ b[c.x], c.x });
                        f[c.x] = 3;
                    } else if (A.a + y.a > B.a + x.a) {
                        ans += A.a + y.a;
                        if (f[A.x] == 2)
                            ++tot;
                        cha(A);
                        chb(y);
                        f[A.x] |= 1;
                        f[y.x] |= 2;
                    } else {
                        ans += B.a + x.a;
                        if (f[B.x] == 1)
                            ++tot;
                        cha(x);
                        chb(B);
                        f[B.x] |= 2;
                        f[x.x] |= 1;
                    }
                }
            }
            printf("%lld
    ", ans);
        }
    }
    
  • 相关阅读:
    centos 配置php
    Linux下端口被占用解决
    LUOGU P1040 加分二叉树
    bzoj 1057: [ZJOI2007]棋盘制作
    1858: [Scoi2010]序列操作
    poj 2559 Largest Rectangle in a Histogram
    2018/7/19 模拟赛
    SPOJ 2916 GSS5
    BZOJ 4004: [JLOI2015]装备购买
    CF 549B Looksery Party
  • 原文地址:https://www.cnblogs.com/invisible-eyes/p/13232474.html
Copyright © 2011-2022 走看看