【洛谷习题】丢瓶盖

题目链接:https://www.luogu.org/problemnew/show/P1316


 

刷新我对二分答案理解的二分答案题!

根据问法这是道二分答案题,嗯事实证明确实如此。然后我们分两个过程研究。

第一是二分边界的处理。之前我一直使用的是闭区间,结果在这翻车了,我之前还以为闭区间是万能的,左闭右开是不完美的!!!额,原因在于闭区间对于边界的处理十分严格,编程语言的缘故,就会出现死循环等不可描述的错误。

解决办法是区间不要卡得太严格,要写成mid=l+(r-l+1)/2。当然也可以改成左闭右开,就比较自然了。后来发现,其实两种方法在不同的情况下并不一定正确,一个比较不正式的方法是,两种方法都试试。

第二点就是验证了。一开始我很纠结,两个瓶盖的最短距离必须保证存在啊,仔细考虑后发现,最大的最短距离一定是存在的,就是说一定有两个瓶盖的距离是他,否则,会存在两个瓶盖的距离比这个答案还大。

再就是,验证时,我们从1开始暴力验证,能取就取,真的对吗?应该是对的,要么符合答案的取法里有1,要么没有,如果没有,若答案会取的那个在1的下一块之后,那么和1就没有什么关系了,若刚好是1的下一块,显然取1会更优(当然,如果答案不是1和其下一块的距离,和1就更没有关系了)。

呃呃,还要注意将坐标排序,题目描述并不保证是顺序的。

 1 #include <cstdio>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 const int maxn = 1e5 + 5;
 7 
 8 int a, b, cap[maxn];
 9 
10 inline int min(int a, int b) {return a < b ? a : b;}
11 
12 inline int check(int x) {
13     int cnt = 1, last = 1;
14     for (int i = 2; i <= a; ++i)
15         if (cap[i] - cap[last] >= x) ++cnt, last = i;
16     if (cnt >= b) return 1;
17     else return 0;
18 }
19 
20 int main() {
21     scanf("%d%d", &a, &b);
22     for (int i = 1; i <= a; ++i)
23         scanf("%d", &cap[i]);
24     sort(cap + 1, cap + a + 1);
25     int l = 0, r = cap[a] - cap[1], mid;
26     while (l < r - 1) { //左闭右开写法
27         mid = l + (r - l) / 2;
28         if (check(mid)) l = mid;
29         else r = mid;
30     }
31     printf("%d", l);
32     return 0;
33 }
AC代码

 

posted @ 2018-10-12 11:51  Mr^Kevin  阅读(193)  评论(0编辑  收藏  举报