「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
", 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
", u1, u2, v1, v2, w);
//printf("%d %d %d
", 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
", h1.size());
//printf("%d %d %d
", 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
", 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
", work());
}
return 0;
}