牛客3402E-一步兩步是魔鬼的步伐-二分

題目描述:

鏈接: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)塊石頭,不過皮卡丘沒有告訴假面騎士到底去掉了哪些位置的石頭。

假面騎士想知道在過河的過程中,他需要跨越的最小距離最大可能是多少。

輸入描述:

有多組測試,保證 Ni5106\sum N_i \leq 5*10^6;
每個測試的第一行是河的寬度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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章