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 1N105

  • 1 ≤ M ≤ N 2 1\\leq M\\leq N ^2 1MN2

  • 1 ≤ A i ≤ 1 0 5 1\\leq A_i\\leq 10^5 1Ai105

  • 所有输入的数都是整数

样例解释:

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集训队每周程序设计竞赛题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛(13)题解

2021-2022-2 ACM集训队每周程序设计竞赛 - 问题 C:回到学校 - 题解

2021-2022-2 ACM集训队每周程序设计竞赛(10) - 问题 C: 下一个素数 - 题解