「NOI2019d1t3」序列

「NOI2019d1t3」序列

题目链接

\(Description\)

长度为 \(n \ (n \leq 10 ^ 6)\) 的两个序列 \(a, b\),要求各选 \(K \ (K \leq n)\) 个数满足条件:

至少有 \(L \ (L \leq K)\) 个数在序列中的位置相同;

满足上述条件时,使得选出数的和最大。

输出最大的和。

\(Solution\)

显然可以费用流,模型如下:

\(S - A_i \ (1, a_i)\)\(A_i - B_i \ (1, 0)\)\(B_i - R \ (1, b_i)\)\(R - T \ (K, 0)\)

\(A_i - P \ (1, 0)\)\(P - Q \ (K - L, 0)\)\(Q - B_i \ (1, 0)\)

如果 \(P - Q\) 未流满,先考虑它肯定最优;

如果流满,那么只有两种选择:

1.选位置相同的一对;
2.选 \(A\) 中的最大值 \(A_i\)\(B\)\(A_j\) 已经被选过的最大值 \(B_j\),反之同理。

如果某一对 \(A_i\)\(B_i\) 在两此不同的增广里被选择,就不占用 \(P-Q\) 的流量。

模拟上述过程即可。

时间复杂度:\(O (T n \log_2 n)\)

\(Source\)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
int in() {
    int x = 0; char c = getchar(); bool f = 0;
    while (c < '0' || c > '9')
        f |= c == '-', c = getchar();
    while (c >= '0' && c <= '9')
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 1e6 + 5;

int n, K, L;
int a[N], b[N];

typedef std::pair<int, int> pii;
std::priority_queue<pii> q1, q2, h1, h2, q;
int vis1[N], vis2[N];

void prep() {
    memset(vis1, 0, sizeof(vis1));
    memset(vis2, 0, sizeof(vis2));
    while (!q1.empty()) q1.pop();
    while (!q2.empty()) q2.pop();
    //printf("%d\n", h1.size());
    while (!h1.empty()) h1.pop();
    while (!h2.empty()) h2.pop();
    while (!q.empty()) q.pop();
    for (int i = 1; i <= n; ++i) {
        q1.push(pii(a[i], i)), q2.push(pii(b[i], i));
        q.push(pii(a[i] + b[i], i));
    }
}

long long work() {
    long long ret = 0;
    int now = 0;
    for (int i = 1; i <= K; ++i) {
        if (now < K - L) {
            int u, v;
            while (!q1.empty()) {
                u = q1.top().second; q1.pop();
                if (!vis1[u])
                    break;
            }
            while (!q2.empty()) {
                v = q2.top().second; q2.pop();
                if (!vis2[v])
                    break;
            }
            if (u != v) {
                if (!vis2[u])
                    h2.push(pii(b[u], u));
                if (!vis1[v])
                    h1.push(pii(a[v], v));
            }
            if (vis2[u] && vis1[v])
                --now;
            else if (!vis2[u] && !vis1[v] && u != v)
                ++now;
            vis1[u] = vis2[v] = 1;
            ret += a[u] + b[v];
        } else {
            int u1 = 0, u2 = 0, s1 = 0;
            while (!q1.empty()) {
                u1 = q1.top().second;
                if (!vis1[u1])
                    break;
                q1.pop();
            }
            while (!h2.empty()) {
                u2 = h2.top().second;
                if (!vis2[u2])
                    break;
                h2.pop();
            }
            if (u2 && !vis2[u2])
                s1 = a[u1] + b[u2];

            int v2 = 0, v1 = 0, s2 = 0;
            while (!q2.empty()) {
                v2 = q2.top().second;
                if (!vis2[v2])
                    break;
                q2.pop();
            }
            while (!h1.empty()) {
                v1 = h1.top().second;
                if (!vis1[v1])
                    break;
                h1.pop();
            }
            if (v1 && !vis1[v1])
                s2 = a[v1] + b[v2];

            int w = 0, s3 = 0;
            while (!q.empty()) {
                w = q.top().second;
                if (!vis1[w] && !vis2[w])
                    break;
                q.pop();
            }
            if (!vis1[w] && !vis2[w])
                s3 = a[w] + b[w];

            //printf("%d %d  %d %d  %d\n", u1, u2, v1, v2, w);
            //printf("%d %d %d\n", s1, s2, s3);
            if (w && s3 > s1 && s3 > s2) {
                q.pop();
                vis1[w] = vis2[w] = 1;
                ret += s3;
            } else if (s1 >= s3 && (s1 > s2 || (s1 == s2 && vis2[u1] > vis1[v2]))) {
                q1.pop(), h2.pop();
                vis1[u1] = 1, vis2[u2] = 1;
                if (vis2[u1])
                    --now;
                else
                    h2.push(pii(b[u1], u1));
                ret += s1;
            } else {
                //printf("%d\n", h1.size());
                //printf("%d %d %d\n", s1, s2, s3);
                q2.pop(), h1.pop();
                vis2[v2] = 1, vis1[v1] = 1;
                if (vis1[v2])
                    --now;
                else
                    h1.push(pii(a[v2], v2));
                ret += s2;
            }

        }
        //printf("%d %d\n", u, v);
    }
    return ret;
}

int main() {
    //freopen("in", "r", stdin);
    //freopen("out2", "w", stdout);
    int tim = in();
    while (tim--) {
        n = in(), K = in(), L = in();
        for (int i = 1; i <= n; ++i)
            a[i] = in();
        for (int i = 1; i <= n; ++i)
            b[i] = in();
        prep();
        printf("%lld\n", work());
    }
    return 0;
}
posted @ 2020-05-28 18:55  15owzLy1  阅读(170)  评论(0编辑  收藏  举报