牛客——签到题

分析

我拿到题就去看了示例,可以发现,并非是让难度最小,或者难度系数出现次数最多的成为签到题的难度。那我就有点懵了。。。。。。

但仔细观察题目本身的特定条件和目标,即在满足选择 m 道题的前提下,尽可能多地选择难度值最低的题目,可以想到贪心

贪心算法在这种情况下适用,因为它能够在每一步选择中做出局部最优的选择,从而达到全局的最优解。

具体的思考过程:

1. 理解题目要求

题目要求我们从题库中选择 m 道题,并希望这些题目的难度尽可能低。这里的关键是“尽可能低”,意味着我们应该优先选择难度值最小的题目。

2. 分析题目数据

题目中给出的是一个难度值列表,每个难度值对应一定数量的题目。我们需要从这些题目中选择 m 道题。

3. 贪心策略的适用性

贪心算法适用于那些可以通过局部最优选择达到全局最优解的问题。在这个问题中,局部最优选择是每次选择当前难度值最小的题目,因为这样可以确保我们尽可能多地选择低难度的题目。

4. 贪心策略的具体实现

  • 从低到高选择:从难度值最小的题目开始选择,逐步增加难度值,直到选出 m 道题或无法再选择更多题目。

  • 记录最大签到题数量:在满足选择 m 道题的条件下,记录能够选择的难度值最小的题目的最大数量。

5. 为什么贪心算法有效

  • 单调性:选择难度值最小的题目是一个单调递增的过程,即随着难度值的增加,我们选择的题目数量不会减少。

  • 最优子结构:每一步的局部最优选择(选择当前难度值最小的题目)保证了全局的最优解。

6. 代码实现

代码通过从难度值最大的题目开始累加,直到累加的题目数量达到或超过 m,然后记录当前难度值的题目数量。这样做实际上是在尝试找到满足条件的最低难度值,因为一旦找到满足条件的难度值,就没有必要再考虑更高难度值的题目。

7. 结论

通过贪心算法,我们可以有效地解决这个问题,因为它能够在每一步都做出最优的选择,从而在全局上达到最优解。这种方法简单、直观,且易于实现,非常适合这类优化问题。

代码

#include<bits/stdc++.h>
using namespace std;
int a[200005];
int main(){
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++){
        int x;
        cin>>x;
        a[x]++;
    }
    int ans=0,sum=0;
    for(int i=n;i>=1;i--){//从最大难度值开始遍历,是为了让最终签到题难度尽可能小
        sum+=a[i];//sum用来判断在这个难度下是否已经选够了m题
        if(sum>=m){  //只有这种情况下才可更新ans
            ans=max(a[i],ans);
        }
    }
    cout<<min(ans,m);
    return 0;
}

碎碎念

我一直不太理解为什么要有sum>=m这一个判断条件,其实是因为我们是从大到小从n道题中选择m道,而且要求签到题难度尽可能小,数量尽可能多,有人肯定回想n一定大于m,所以一定可以选够m道题,其实代码逻辑不是这样想的,我们是从大到小从n道题中一题一题选择的,因为贪心遵循每次选择都是最优解,即每次选择当前难度值最小的题目,而不是从n道中任意选m,所以只有选择的题数大于等于m,才可以确保在找到满足条件的最低难度值时更新 ans,如果没有这个条件,代码可能会在没有满足选择 m 道题的情况下更新 ans。这会导致最终结果不满足题目要求,即没有选出足够的题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值