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);
        }
    }
    
  • 相关阅读:
    剑指Offer-30.连续子数组的最大和(C++/Java)
    剑指Offer-29.最小的K个数(C++/Java)
    UVA 1616 Caravan Robbers 商队抢劫者(二分)
    UVA 10570 Meeting with Aliens 外星人聚会
    UVA 11093 Just Finish it up 环形跑道 (贪心)
    UVA 12673 Erratic Expansion 奇怪的气球膨胀 (递推)
    UVA 10954 Add All 全部相加 (Huffman编码)
    UVA 714 Copying Books 抄书 (二分)
    UVALive 3523 Knights of the Round Table 圆桌骑士 (无向图点双连通分量)
    codeforecs Gym 100286B Blind Walk
  • 原文地址:https://www.cnblogs.com/invisible-eyes/p/13232474.html
Copyright © 2011-2022 走看看