題目描述:
鏈接:https://ac.nowcoder.com/acm/contest/3402/E
來源:牛客網
數據已修改,比賽時的所有提交已經進行了rejudge。
假面騎士要過河,恰好河的兩岸間有N(0 ≤ N ≤ 50,000)塊石頭在同一條直線上。他已經知道了河的寬度L(1 ≤ L ≤ 1,000,000,000)和每一塊石頭離假面騎士所在河岸的距離Di(0 < Di < L),石頭不會發生重疊。
可是假面騎士在與怪物的激烈戰鬥之後,留下了後遺症。他不能忍受跨越任何一塊石頭,所以他只能一塊一塊地按距離順序踩着石頭過河。皮卡丘是他的好朋友,皮卡丘爲了幫助他,已經使用十萬伏特去掉了M (0 ≤ M ≤ N)塊石頭,不過皮卡丘沒有告訴假面騎士到底去掉了哪些位置的石頭。
假面騎士想知道在過河的過程中,他需要跨越的最小距離最大可能是多少。
輸入描述:
有多組測試,保證 ;
每個測試的第一行是河的寬度L,石頭總數N,被消滅石頭的個數M
第二行有N個數,表示每塊石頭到假面騎士所在河岸的距離
輸出描述:
輸出在所有可能的情況下,需要跨越的最小距離最大可能是多少
輸入樣例:
5 2 1
3 4
25 5 2
2 14 11 21 17
輸出樣例:
2
4
核心思想:
二分距離,對於每一個距離x:
以cnt記錄被刪除石頭的數目,
先自近向遠遍歷,如果石頭i和上一個被保留下的石頭的距離不小於x,則石頭i可以被保留,否則刪掉。
再自遠向近遍歷,如果石頭i與目的河岸的距離小於x,則刪除石頭i,否則遍歷結束。
若cnt不大於m,則x可行,否則x不可行,分情況縮小二分區間。
代碼如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=5e4+20;
int d,n,m,a[N],b[N];//a存原數組,b存保留下的數
bool fun(int x)
{
int p=0,cnt=0;
b[p++]=0;
for(int i=1;i<=n&&cnt<=m;i++)//自近向遠選數
if(a[i]-b[p-1]<x) cnt++;
else b[p++]=a[i];
if(cnt>m) return 0;
for(int i=p-1;i>0&&d-b[i]<x;i--,cnt++);//自遠向近刪數
if(cnt>m) return 0;
return 1;
}
int main()
{
while(cin>>d>>n>>m)
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);//a數組原本是亂序的
int l=0,r=d,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(fun(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}