【洛谷习题】丢瓶盖
题目链接: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 }