「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;
}