2021-2022-2 ACM集训队每周程序设计竞赛(10) - 问题 E: 十万人如何交换名片- 题解
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-2 ACM集训队每周程序设计竞赛(10) - 问题 E: 十万人如何交换名片- 题解相关的知识,希望对你有一定的参考价值。
传送门
十万人如何交换名片
时间限制:3秒
空间限制:128M
题目描述
这是一个日本的创意广告,讲述了一百个人如何交换名片(与此题无关,可自行决定是否观看)https://www.bilibili.com/video/BV1wS4y1m7sM:
20202年疫情结束,小T作为人类记忆的载体,登上了三体星球。
三体人都十分欢迎小T,每人都用两种语言准备了自己的名片(左手地球语言🌏,右手三体语言🪐)
但是三体人太多了,一共有N(N ≤ 100000)个,小T决定只收取M次名片。
每次,小T都会这样收取名片:
- 用左手收取三体人x右手中的名片🪐
- 用右手收取三体人y左手中的名片🌏
并将这次名片收取行动记为(x, y)
这样,三体人与地球人的好感度就会增加 A x + A y A_x + A_y Ax+Ay。
小T想最大化三体人与地球人的亲密度,但是为了避免其他三体人的嫉妒,小T的M次名片收取行动必须各不相同。
也就是说,不能存在两次名片收取行动(x1, y1)和(x2, y2),满足x1 = x2 且 y1 = y2
但是,x1可以等于y1(也就是说一次名片收取行动中可以左手右手收取同一三体人的名片)
那么经过M次名片收取活动后,地球人与三体人的亲密度增加了多少呢?
输入描述
输入格式:
N M
A1 A2 ... AN
N代表一共有N个三体人,M代表一共收取M次名片。
Ai代表收取一张三体人i的名片,亲密度将会增加Ai(1 ≤ i ≤ N)
数据范围:
-
1 ≤ N ≤ 1 0 5 1 \\leq N \\leq 10^5 1≤N≤105
-
1 ≤ M ≤ N 2 1\\leq M\\leq N ^2 1≤M≤N2
-
1 ≤ A i ≤ 1 0 5 1\\leq A_i\\leq 10^5 1≤Ai≤105
-
所有输入的数都是整数
样例解释:
5 3
10 14 19 34 33
三体星球共有5个三体人,小T共收取3次名片
- 小T每收取一张三体人1的名片,三体人与地球人的亲密度就会增加10
- 小T每收取一张三体人2的名片,三体人与地球人的亲密度就会增加14
- 小T每收取一张三体人3的名片,三体人与地球人的亲密度就会增加19
- 小T每收取一张三体人4的名片,三体人与地球人的亲密度就会增加34
- 小T每收取一张三体人5的名片,三体人与地球人的亲密度就会增加33
输出描述
输出一行一个正整数,代表小T进行M次名片收取行动最多能让三体人和地球人的亲密度增加多少。
样例解释:
在上述样例中:
- 第一次小T左手收取三体人4右手中的名片🪐,右手收取三体人4左手中的名片🌏,并记为(4, 4)
- 第二次小T左手收取三体人4右手中的名片🪐,右手收取三体人5左手中的名片🌏,并记为(4, 5)
- 第三次小T左手收取三体人5右手中的名片🪐,右手收取三体人4左手中的名片🌏,并记为(5, 4)
因此亲密度会增加(34 + 34) + (34 + 33) + (33 + 34) = 202。
找不到亲密度增加多于202的方法。
因此输出:
202
样例一
输入
5 3
10 14 19 34 33
输出
202
样例二
输入
9 14
1 3 5 110 24 21 34 5 3
输出
1837
样例三
输入
9 73
67597 52981 5828 66249 75177 64141 40773 79105 16076
输出
8128170
题目分析
如果暴力枚举最大的M次名片收取所获得的好感度并求和,那么显然会超时。
但是,单次名片收取活动最多增加 2 × 1 0 5 2\\times 10^5 2×105的好感度,因此我们可以用二分的方法来解决。
首先: 对于一个给定的好感度X,有多少种名片收取方式可以使得 单次 的好感度≥X呢?
想要解决这个小问题,我们只需要从1到N枚举这N个三体人,用左手收取这个三体人(记为i)右手的名片🪐,并获得Ai的好感度。(时间复杂度 O ( N ) O(N) O(N))
然后,对于三体人i,收取他右手的名片🪐已经获得了Ai的好感度,想要此次名片收取活动所获得的好感度≥X,右手收取的名片🌏至少获取 X - Ai 的好感度。因此我们只需要对排好序的三体人好感度进行一次二分,即可在 O ( log N ) O(\\log N) O(logN)的时间内找到第一个好感度 ≤ X - Ai 的三体人的编号。
解决此问题总共的时间复杂度是 O ( N log N ) O(N\\log N) O(NlogN)
然后: 我们只需要从0到 2 × 1 0 5 2\\times 10^5 2×105二分X,找到单次名片收取获得好感度 ≥ X的方案数不小于M的最小的X。( 2 21 = 2097152 2^21=2097152 221=2097152,这是个常数级别的复杂度)
假如:
- 单次名片交换亲密度大于6的方式有2种
- 单次名片交换亲密度大于5的方式有3种
- 单次名片交换亲密度大于4的方式有3种
- 单次名片交换亲密度大于3的方式有5种
那么进行3次名片收取活动所要寻找的X就是4
同时,在计算过程种我们用变量Sum、cnt记录一些数据:
Sum:单次好感度≥X的名片交换,所获得的好感度的总和
cnt:单次好感度≥X的名片交换方案数
那么:
cnt - M:名片交换次数比M次多的次数
那么:
Sum - (cnt - M) * X即为答案
AC代码
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
const int N = 1e5 + 5;
ll sum[N], a[N], m, n;
int main()
cin >> n >> m;
for (ll i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
for (ll i = 1; i <= n; i++)
sum[i] = sum[i - 1] + a[i]; // sum:前缀和,sum[r] - sum[l - 1]代表[l, r]的a的和
ll l = 0, r = 2e5 + 1, X, Sum, cnt;
while (l <= r)
ll mid = (l + r) >> 1;
Sum = cnt = 0;
for (ll i = 1; i <= n; i++)
ll pos = lower_bound(a + 1, a + n + 1, mid - a[i]) - a;
cnt += n - pos + 1; // 左手收取三体人i的名片的话,右手有n - pos + 1种方法收取名片,使得每次名片收集所获得的好感度都不小于X
Sum += sum[n] - sum[pos - 1] + a[i] * (n - pos + 1); // 右手获得的好感度的总和是sum[n] - sum[pos - 1],左手获得的好感度的总和是a[i] * (n - pos + 1)
if (cnt >= m) // 如果方案数不小于m
X = mid;
l = mid + 1;
else
r = mid - 1;
cout << Sum - (cnt - m) * X << endl;
return 0;
点关注,不迷路
原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/124565988
以上是关于2021-2022-2 ACM集训队每周程序设计竞赛(10) - 问题 E: 十万人如何交换名片- 题解的主要内容,如果未能解决你的问题,请参考以下文章
2021-2022-2 ACM集训队每周程序设计竞赛(13)题解
2021-2022-2 ACM集训队每周程序设计竞赛(13)题解
2021-2022-2 ACM集训队每周程序设计竞赛(13)题解