题解:CF1976C Job Interview
Part 1:题目理解
地址链接
洛谷。
题目翻译
一家公司要招 n n n 个程序员和 m m m 个测试员。现在有 n + m + 1 n + m + 1 n+m+1 个人按照编号顺序先后前来应聘。第 i i i 个人的编程能力和测试能力分别为 a i a_i ai 和 b i b_i bi(保证 a i ≠ b i a_i \neq b_i ai=bi)。对于第 i i i 个人,如果 a i > b i a_i > b_i ai>bi,那么如果还有程序员岗位就让他当程序员,否则只能当测试员;如果 a i < b i a_i < b_i ai<bi 就同理反之。该公司的能力定义为:程序员的 a i a_i ai 之和加上测试员的 b i b_i bi 之和。问,对于每一个 1 ≤ i ≤ n + m + 1 1 \leq i \leq n + m + 1 1≤i≤n+m+1,如果编号为 i i i 的人不来应聘,公司的能力为多少?
数据范围
∑ n ≤ 2 ⋅ 1 0 5 \sum n \leq 2 \cdot 10 ^ 5 ∑n≤2⋅105。
Part 2:思路分析
先直接模拟求出第
n
+
m
+
1
n + m + 1
n+m+1 个人不来时公司的能力值(记作 ans
)。在此过程中,记录每一个人的职位(记作 use[i]
),并把本应该当程序员由于人数原因当了测试员的和本应该当测试员由于人数原因当了程序员的人的编号扔入两个 set
(分别记作 st[0/1]
)。这两件事以后自有妙用。
处理完上述内容后就可以求每个
1
≤
i
≤
n
+
m
+
1
1 \leq i \leq n + m + 1
1≤i≤n+m+1 的答案了。当
i
=
n
+
m
+
1
i = n + m + 1
i=n+m+1 时,答案自然为 ans
。否则,第
i
i
i 个人的缺席就导致其后面多出了一个 use[i]
的岗位。如果存在一个
j
>
i
j > i
j>i 使得第
j
j
j 个人本应该当 use[i]
却因为人数原因当了 use[j]
(use[i]
不等于 use[j]
),那么就让
j
j
j 当 use[i]
,并让多余的
n
+
m
+
1
n + m + 1
n+m+1 当 use[j]
,答案为 ans - a[i][use[i]] + a[j][use[i]] - a[j][use[j]] + a[n + m + 1][use[j]]
;如果不存在,就直接让
n
+
m
+
1
n + m + 1
n+m+1 当 use[i]
,答案为 ans - a[i][use[i]] + a[n + m + 1][use[i]]
。对于
j
j
j 的情况,我们用 upper_bound
来实现。
Part 3:代价估计
记
n
n
n 和
m
m
m 为同级别的
k
k
k,因为用到了 set
所以时间复杂度为
O
(
k
⋅
log
(
k
)
)
O(k \cdot \log(k))
O(k⋅log(k))。
Part 4:代码编写
#include <bits/stdc++.h>
#define N 220000
#define M 220000
using namespace std;
int t, n, m, a[N + M + 1][2];
int s[2], use[N];
long long ans;
set<int> st[2];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n + m + 1; i++) {
scanf("%d", &a[i][0]);
}
for (int i = 1; i <= n + m + 1; i++) {
scanf("%d", &a[i][1]);
}
ans = 0;
s[0] = 0;
s[1] = 0;
st[0].clear();
st[1].clear();
for (int i = 1; i <= n + m; i++) {
if (a[i][0] > a[i][1]) {
if (s[0] < n) {
s[0]++;
use[i] = 0;
ans += a[i][0];
} else {
s[1]++;
use[i] = 1;
ans += a[i][1];
st[0].insert(i);
}
} else {
if (s[1] < m) {
s[1]++;
use[i] = 1;
ans += a[i][1];
} else {
s[0]++;
use[i] = 0;
ans += a[i][0];
st[1].insert(i);
}
}
}
for (int i = 1; i <= n + m; i++) {
int w = use[i];
auto it = st[w].upper_bound(i);
if (it == st[w].end()) {
printf("%lld ", ans - a[i][w] + a[n + m + 1][w]);
} else {
printf("%lld ", ans - a[i][w] + a[*it][w] - a[*it][1 - w] + a[n + m + 1][1 - w]);
}
}
printf("%lld\n", ans);
}
return 0;
}