题解 P6174 【[USACO16JAN]Angry Cows S】

SingularPoint

2020-11-10 19:30:04

Solution

### 题目大意 给出直线上的若干点和炸弹数量,求一个炸弹能够影响到的**最小半径**,使得在规定的数量内炸弹可以覆盖所有点。 ### 分析 一读题就是二分答案啊( ------ #### 二分答案 适用范围:求能使的题目所述条件得到满足的答案的**最值**。 前提条件:答案在区间内有**单调性**。 实现方式:先确定答案所在的数据范围,每次**取区间的中点数值**,并询问这个值能否用做答案,以此为基础逐步缩小答案的范围,最后使得区间的左右边界重合或左右交换,此时的边界数值就是所求的答案啦~ 二分答案在适用的条件下只用几十次询问就可以得到答案,经常与DP等算法放在一起考察,能够对题目进行很好的简化,是一种常用的算法思想。 ------ 本题就是一道典型的二分答案题,我们**每次二分炸弹的爆炸半径**,其最小为一,最大就是当前所有点坐标的最值之差除以二(然鹅本人代码里用的是最大点坐标QAQ) 判断是否符合条件时直接模拟就可以啦~ 我在这里用了贪心的思想,把炸弹认为是一个区间的话,这个炸弹的最大效用一定是在它以当前最近的点的作为区间起点的时候,以此来进行对答案可行性的判断。 分析结束就上代码罢 ### Code ```cpp #include<bits/stdc++.h> #define ull uneigned long long #define ll long long #define db double using namespace std; const int M=50005; int n,m; int a[M]; bool check(int x) { int len=a[1]+x*2,cnt=1; for(int i=1;i<=n;i++){ if(a[i]<=len) continue; else{ len=a[i]+2*x; cnt++; } if(cnt>m) return 0;//当此时用到的炸弹数量大于题目条件时return } return 1; } int main() { scanf("%d%d",&n,&m); int l=1,r=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1);//将点的位置从小到大排序 r=a[n]; while(l<=r){//二分答案 int mid=(l+r)>>1; if(check(mid)) r=mid-1; else l=mid+1; } printf("%d",l);//要输出左边界,输出右边界会导致错误的(原因可以自己手动模拟一下) return 0; } ``` 完结撒fa~