题解:CF1976C Job Interview

题解:CF1976C Job Interview

Part 1:题目理解

地址链接

洛谷

CodeForces

题目翻译

一家公司要招 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 1in+m+1,如果编号为 i i i 的人不来应聘,公司的能力为多少?

数据范围

∑ n ≤ 2 ⋅ 1 0 5 \sum n \leq 2 \cdot 10 ^ 5 n2105

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 1in+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 juse[i],并让多余的 n + m + 1 n + m + 1 n+m+1use[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+1use[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(klog(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;
}
  • 21
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值