很水的一道题?为什么我觉得很难??
思路是二分,二分谁呢?
题目的意思是给一段区间,已经插了几个点了,然后再插几个点,问使所有小区间的最大值最小的这个最大值是多少,即空旷指数
做法非常巧妙。
要求的是这个最大值,就能二分查找最大值。
左右端点?
l=0没话说,r=len区间长度也没话说。
但是l<r的时候,r不需要加1(证明过了能AC),因为最右区间端点已经有路标了。这个无所谓
所以思路就是二分这个所有小区间的最大值。
但是也不是直接二分答案,而是通过路标的数量来间接计算:假设设置一个mid作为空旷指数,如果根据这个空旷指数算出来的路标数大于题目给的路标数,说明空旷指数太小了,即所有小区间的最大值设置的太小了,这就和空旷指数联系起来了。所以,l=mid+1.
反之如果根据这个空旷指数算出来的路标数小于等于题目给的路标数,说明空旷指数正好或者太大了,需要小一点,即r=mid-1.
好,其实二分的关键出在为什么是大于和小于等于而不是大于等于和小于。大于是路标大于,实际上是空旷指数小于,小于等于也是路标小于等于,实际上是空旷指数大于等于:所以就是分成了小于和大于等于。。。。。。。
然后就是求大于等于的最小值了。
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1011000;
int len,n,m; //公路长度,原有路标数,可增加的路标数
int a[N];
bool check(int mid)
{
int cnt=0;
for(int i=2;i<=n;i++)
{
cnt+=(a[i]-a[i-1]) / mid;
if((a[i]-a[i-1]) % mid==0) //a[i] - a[i-1] 必须加括号!!!
--cnt;
if(cnt>m) return false;//需要的路标数大于给的,设置的空旷指数太小,需要放大 a[mid] < target
}
return true; //cnt<=m,即a[mid] >=target
}
int main()
{
cin>>len>>n>>m;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int l=0,r=len;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) r=mid-1; // 即a[mid] >=target,所以return r是小于,l是大于等于,题目要求大于等于
else l=mid+1;
}
cout<<l;
}