2019 蓝桥杯省赛 A 组模拟赛(一)计蒜客 A2229

题目链接:https://vjudge.net/problem/%E8%AE%A1%E8%92%9C%E5%AE%A2-A2229
某班有 nn 个同学,每个同学有一个外向程度 a_ia
i

。由于要进行某个活动,需要把他们分成若干个小组,每个小组的人数至少为 mm 人。不同外向程度的人在一个小组会产生不开心值,定义一个小组的不开心值为组内成员外向程度最大值和最小值的差,一个班级的不开心值为所有小组不开心值的最大值。

那么问题来了,如何分组使得班级的不开心值最小,请你求出这个最小的班级不开心值。

输入格式
第一行两个整数 n,mn,m,分别表示人数和每个小组最少的人数要求。

第二行 nn 个整数 a_ia
i

,表示每个同学的外向程度。

输出格式
一个整数,表示最小的班级不开心值。

数据范围
对于 30%30% 的数据:1\le m \le n \le 201≤m≤n≤20,1\le a_i \le 1001≤a
i

≤100。

对于 60%60% 的数据:1\le m \le n\le 10001≤m≤n≤1000,1\le a_i \le 10001≤a
i

≤1000。

对于 100%100% 的数据:1\le m\le n \le 5\cdot10^51≤m≤n≤5⋅10
5,1<=ai<=109,1≤a i ≤109

样例解释
第一个样例,只要每个人各自一个组,不开心值就都是 0。

第二个样例,最佳的分组情况为:9,119,11 一个组,6,3,56,3,5 一个组,两个组的不开心值分别为 22 和 33,那么班级的不开心值为 33。

样例输入1
5 1
2 4 6 8 10
样例输出1
0
样例输入2
5 2
9 11 6 3 5
样例输出2
3

emmmmmmmm,题目复制过来显示就不太好了,还是看链接的体面吧。

分析:
一开始我以为是啥子贪心啊,思维题啊,但是……刚了好久,实在是每思路了,然后去找题解了,高高兴兴搜题解呀,那叫一个高兴啊,高…高…兴……………………啊啊啊啊啊啊啊
原谅我实在是没有一眼就看懂这位大佬的题解(此时的我留下了不学无术的眼泪,太菜了)https://blog.csdn.net/qq_41289920/article/details/87032762

大佬是用DP+二分来实现的(这里只是第一个思路,第二个还没看QAQ);

dp[i]代表前i个人已经分好组之后,最后一个可以加入当前分组的人的编号(这里的最后一个人指的是当前组的最后,不一定是第n个人,这点要搞清楚)

二分是用来二分答案的,对于每一个答案,用dp去判断是不是符合条件,也就是当前的二分测试答案X是不是所有组中不开心值的最大值。
下面是我手写的分析过程,可能有些地方理解起来还是有点困难,最好多看几遍。
在这里插入图片描述

AC代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int N = 1e5 + 10;
const int mod = 1e9+7;
int dp[N*5],n,m,a[N*5];
bool Check(int x){
    dp[m]=m;
    for(int i=m+1;i<=n;i++){
        if(a[i]-a[dp[i-m]+1]<=x) dp[i]=i;
        else dp[i]=dp[i-1];
    }
    return dp[n]==n;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n);

    int l=0,r=inf;
    while(l<=r){
      int mid=(l+r)>>1;
        if(Check(mid))
            r=mid-1;
        else
            l=mid+1;
    }
    printf("%d\n",r+1);

    return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值