本来以为自己二分枚举答案求可行解已经比较厉害了,谁知上来就被卡两个小时。。
这题吧。。确实很恶心,边界条件很难控制,许多AC的人都不能证明自己代码的正确性。
先贴代码:
#include<stdio.h> #include<algorithm> typedef long long ll; using namespace std; ll n,m,L,a[100010]; bool bi(ll x){ ll i,cnt=0,now=0; for(i=1;i<=n;i++){ if(a[i]-a[now]<=x)cnt++; else now=i; } if(L-a[now]<x)return 0; return cnt<=m; } int main(){ ll i,l,r,mi; while(~scanf("%lld%lld%lld",&L,&n,&m)){ l=0;r=L; for(i=1;i<=n;i++) scanf("%lld",&a[i]), r+=a[i]; sort(a,a+n+1); while(l<r){ mi=l+r>>1; if(bi(mi))l=mi+1; else r=mi; } printf("%lld\n",r); } return 0; }
二分的就是最小的步长。
这题的关键点在于在取出M个石头之后,牛是要把所有石头都跳一遍的。
那么想象一下,如果规定了最短距离的步长,应该是什么样的情况。
假设牛在now这个石头上,如果a[now+1]-a[now]>=x ,那么now+1这个石头是肯定不会跳的,
那么接下来备选的石头一定是now+2,now+3...直到a[i]-a[now]<x。
那么对于j这个石头来说,是一定要跳到a[j]的,因为当固定了步长x的时候,应该尽量减少去掉的石头数,
这样使得x能尽量大。
所以下一步就应该从a[j]开始枚举,尽量往下跳,
但是对于最后一个石头来说,如果L-a[now]<x 那么说明在这次跳跃过程中,最小步长是L-a[now]而不是x,
因为其他跳跃过程都是按照a[i]-a[now]>x跳的,所以应该减小x,使得L-a[now]>=x 而合法,
所以return 0 使得r=mi。
最后输出。