代码源:80、锦标赛

241 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

这是3月21日代码源div2的每日一题。

锦标赛 - 题目 - Daimayuan Online Judge

题目描述

有n个玩家参加比赛,他们分别有能力值a1,a2,…,an。

需要进行n−1轮比赛,每一轮在剩下的玩家里任选两个玩家i,j。如果|ai−aj|>K,那么其中能力值高的玩家会获胜,能力值低的玩家会被淘汰。如果|ai−aj|≤K,那么两个玩家都有可能获胜,另一个玩家被淘汰。

n−1轮比赛之后,只剩下一个玩家。问有多少个玩家可能是最后获胜的玩家。

输入格式

第一行,两个整数n,K,表示玩家的总人数,和获胜条件中的参数。

接下来一行n个整数a1,a2,…,an,表示玩家的能力值。

输出格式

一个整数,表示最后可能获胜的玩家个数。

样例输入1

5 3
1 5 9 6 3

样例输出1

5

问题分析

这题估摸着很多人对于 “ 如果|ai−aj|≤K,那么两个玩家都有可能获胜,另一个玩家被淘汰 ” 这句话有点疑惑,其实你可以这么理解,如果|ai−aj|≤K,那就由拥有上帝视角的我们来决定谁赢谁输就行,我们这里也就是根据这个来算的最多可能有多少人能胜出。虽然判断获胜的条件有两个,但其实第一个基本用不上,你可以这么想:

能力最大的玩家和能力第二大的玩家,如果他们的差值大于k,那就是最大的获胜,而既然第二大的都赢不了,那不用想其它能力更小的了,这样最终胜出的只能是1个:能力最大的玩家;

但如果第二大的玩家和最大的玩家相差小于等于k,那么这两位都可以胜出,而且只要第三大的和第二大的相差也是小于等于k,那么他们三个人都有可能会获胜:第一大和第二大比完,我们让第二大赢,再让第二大和第三大比,我们让第三大赢。同理第四大也可以以此类推……

由此可推,我们可以知道,最大的获胜人数就是看从最大的能量开始推,看有多少个连着的差都是小于等于k,当有差大于k时,就断开了,因为差值一旦大于k,那么只有大的哪个能赢,小的是无论如何不能活到最后的。小的想赢只能靠我们上帝视角来帮忙,这就必须要差值小于等于k。

(这里写了自定义排序规则让sort降序排,其实没必要这么写,只是个人的习惯)

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>


#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")

#define endl '\n';
typedef long long ll;
typedef pair<int, int>PII;

bool cmp(int a, int b)
{
    return a > b;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, k;
    cin >> n >> k;
    vector<int>v(n);
    for (int i = 0; i < n; i++)
        cin >> v[i];
    sort(v.begin(), v.end(),cmp);
    int res = 1;
    for (int i = 0; i < n-1; i++)
    {
        if (v[i] - v[i + 1] <= k)res++;
        else break;
    }
    cout << res << endl;
    return 0;
}