【洛谷】【二分答案+贪心】P1316 丢瓶盖

【题目描述:】

陶陶是个贪玩的孩子,他在地上丢了A个瓶盖,为了简化问题,我们可以当作这A个瓶盖丢在一条直线上,现在他想从这些瓶盖里找出B个,使得距离最近的2个距离最大,他想知道,最大可以到多少呢?

【输入格式:】

第一行,两个整数,A,B。(B<=A<=100000)

第二行,A个整数,分别为这A个瓶盖坐标。

【输出格式:】

仅一个整数,为所求答案。

 

【算法分析:】

关于单调性的感性证明:

  如果一个mid作为最大值时所选的瓶盖数量 x≥B,即最大值过小导致选取瓶盖过多,

  则答案一定在[mid + 1, r]内

  否则答案在[l, mid]内

满足单调性,可以二分答案。

关于check函数:

在check一个数mid时,check函数返回mid作为最大值时的选取瓶盖数量,

  这里可以做一个优化,即check返回一个bool类型

  当选取的瓶盖数量超过读入的B时,直接返回1,表示二分[mid + 1, r]这个区间

将数据从小到大排序来实现check函数:

  读入有n个元素的序列a,最大值为max

  利用贪心的思想,由于是求最少选取的瓶盖数量,能不选这个瓶盖的时候就不选

  last表示上一次选取的瓶盖位置

  当且仅当 ai - last > max 时,不选取ai会导致最大值变大,last更新成ai,选取的瓶盖个数+ 1

关于上下界的初始化:

  二分时上下界的初始选择可以是[0, INF],最多进行31次查找。

  只选取两个瓶盖时的最大值为amax - amin ,由于数据已经排好序,上界直接初始化成 an - a1 即可

 

【代码:】

 

 1 //丢瓶盖
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int MAXN = 100000 + 1;
 8 const int INF = 0x7fffffff;
 9 
10 int n, m;
11 int a[MAXN];
12 
13 bool check(int num) {
14     int ret = 1, last = a[1];
15     for(int i = 2; i <= n; i++) {
16         if(a[i] - last > num) last = a[i], ret++;
17         if(ret >= m) return true;
18     }
19     return ret >= m;
20 }
21 int main() {
22     scanf("%d%d", &n, &m);
23     int l = 0, r = INF;
24     for(int i = 1; i <= n; i++) {
25         scanf("%d", &a[i]);
26     }
27     sort(a + 1, a + n + 1);
28     r = a[n] - a[1];
29     while(l < r) {
30         int mid = (l + r) >> 1;
31         if(check(mid)) l = mid + 1;
32         else r = mid;
33     }
34     printf("%d\n", l);
35 }

 

posted @ 2018-05-14 17:37  DEVILK  阅读(1611)  评论(0编辑  收藏  举报