二分答案
题目描述
陶陶是个贪玩的孩子,他在地上丢了A个瓶盖,为了简化问题,我们可以当作这A个瓶盖丢在一条直线上,现在他想从这些瓶盖里找出B个,使得距离最近的2个距离最大,他想知道,最大可以到多少呢?
输入输出格式
输入格式:
第一行,两个整数,A,B。(B<=A<=100000)
第二行,A个整数,分别为这A个瓶盖坐标。
这不是2017年衢州市赛的题目么
借用题解里看到的一句话总结一下:“一般看到所谓的最大值最小化或者最小值最大化,一般都是用二分答案进行运算”作者: Lyrics
嗯对了就是这样,二分答案。
二分答案的题呃普及组的似乎就是这样的套路:找一个上下限;写一个check函数;考虑输出 mid / l / r。最后这个还是视情况而定。
本题的话,check函数不难写出,不过我卡在了最后的这个输出上面。因为以前有写二分的“阴影”,调试的时候先把三个都列出来了。呃,还有那个调整上下限的问题,我印象里"l=mid"/"l=mid+1"在不同的题目里都有出现。于是乎调整了很久(有调将近二十分钟),最后没有办法打了个类似于补丁一样的东西上去(好吧这的确很不“计算机程序设计艺术”),大号提交的是这份:
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 int a[100035],n,m;
5 int l,r,mid,lm,la,cnt;
6 int main()
7 {
8 scanf("%d%d",&n,&m);
9 for (int i=1; i<=n; i++)scanf("%d",&a[i]);
10 sort(a+1, a+n+1);
11 l=0;r=a[n]-a[1];lm = -1;
12 while (l <= r)
13 {
14 mid = (l + r) >> 1;
15 if (mid == lm)break;
16 la=1;cnt=1;
17 for (int i=2; i<=n; i++)
18 if (a[i] - a[la] >= mid){
19 cnt++;la = i;
20 }
21 if (cnt < m)r = mid-1;
22 else l = mid+1;
23 lm = mid;
24 // printf("%d %d %d
",l,r,mid);
25 }
26 {
27 while(cnt < m)
28 {
29 mid--;
30 la=1;cnt=1;
31 for (int i=2; i<=n; i++)
32 if (a[i] - a[la] >= mid){
33 cnt++;la = i;
34 }
35 }
36 }
37 printf("%d",mid);
38 return 0;
39 }
嗯,地地道道的丑陋……
看了一下题解,突然想起来这里求最大值,所以不用费神这么多,输出r就行了。不过当时在前几次的调试之后(调整上下限的还没成型),发现l,r都不对,最后决定改成mid了……
小号份ViewCode
噫,好吧二分是不太熟了
1 笨蛋我的方法 2 int main() 3 { 4 l=0;r=a[n]-a[1];lm = -1; 5 while (l <= r) 6 { 7 mid = (l + r) >> 1; 8 if (mid == lm)break; 9 la=1;cnt=1; 10 for (int i=2; i<=n; i++) ... 11 if (cnt < m)r = mid-1; 12 else l = mid+1; 13 lm = mid; 14 } 15 { 16 while(cnt < m) 17 { 18 mid--; 19 la=1;cnt=1; 20 for (int i=2; i<=n; i++) 21 if (a[i] - a[la] >= mid){ 22 cnt++;la = i; 23 } 24 } 25 } 26 printf("%d",mid); 27 return 0; 28 } 29 30 31 聪明你的方法 32 l=0;r=a[n]-a[1]; 33 while (l <= r) 34 { 35 mid = (l + r) >> 1; 36 la=1;cnt=1; 37 for (int i=2; i<=n; i++) 38 if (a[i] - a[la] >= mid){ 39 cnt++;la = i; 40 } 41 if (cnt < m)r = mid-1; 42 else l = mid+1; 43 } 44 printf("%d",r); 45 return 0;