【问题描述】
为了掩护大部队,英雄Lucky被敌人包围在某山头。但他有足够的弹药,凭借自己的勇敢,完全可以将涌上来的敌人一个一个干掉。Lucky是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑,Lucky会等待敌人靠近然后射击。
正当Lucky为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花K秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时Lucky无法将他击毙,那么我们可怜的Lucky就将牺牲在敌人的刺刀下。现在Lucky向你发出求助:要保住自己的性命并且歼灭所有敌人,Lucky最多只能用多少时间给枪装上一发子弹?
说明:假设一开始Lucky的枪中就有一发子弹,并且一旦确定一个装弹时间,Lucky始终会用这个时间完成子弹的装卸。希望你能帮助Lucky脱离险境。
【输入格式】
第一行有两个整数n和m,n代表敌人个数,m代表Lucky的射程。接下来有n行,每行一个整数di,代表每个敌人一开始相对山头的距离(单位为米)。
【输出格式】
仅有一个整数,代表Lucky的换弹时间(单位为秒)。
【输入样例】
6 100
236
120
120
120
120
120
【输出样例】
25
【数据范围】
50%的数据有:2<=n<=1000
为了掩护大部队,英雄Lucky被敌人包围在某山头。但他有足够的弹药,凭借自己的勇敢,完全可以将涌上来的敌人一个一个干掉。Lucky是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑,Lucky会等待敌人靠近然后射击。
正当Lucky为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花K秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时Lucky无法将他击毙,那么我们可怜的Lucky就将牺牲在敌人的刺刀下。现在Lucky向你发出求助:要保住自己的性命并且歼灭所有敌人,Lucky最多只能用多少时间给枪装上一发子弹?
说明:假设一开始Lucky的枪中就有一发子弹,并且一旦确定一个装弹时间,Lucky始终会用这个时间完成子弹的装卸。希望你能帮助Lucky脱离险境。
【输入格式】
第一行有两个整数n和m,n代表敌人个数,m代表Lucky的射程。接下来有n行,每行一个整数di,代表每个敌人一开始相对山头的距离(单位为米)。
【输出格式】
仅有一个整数,代表Lucky的换弹时间(单位为秒)。
【输入样例】
6 100
236
120
120
120
120
120
【输出样例】
25
【数据范围】
50%的数据有:2<=n<=1000
100%的数据有:2<=n<=100,000; 1<=m<=10,000,000;1<=di<=10,000,000
解题思路:根据题意,要求最小换弹时间最大,主要算法肯定是求最小值最大问题的二分猜答案,对于每猜一个换弹时间,如果可行,则可以换弹时间再猜大点,如果不可行,换弹时间就要猜小点。这道题的难点在于如何判断猜的换弹时间是否可行,我们可以用一个变量tmp来记录当前Lucky所用的时间,先将敌人按相对山头的距离由小到大排序,然后从第二个敌人开始枚举(第一个敌人只要进入射程,就可以直接被射杀),先计算tmp,如果tmp大于该敌人到山头的时间,则答案不可行,否则就看下一个敌人。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=100005;
int N,M;
int d[maxn];
bool check(int m) //判断猜的换弹时间是否可行
{
int tmp=0; //记录当前Lucky所用的时间
if(d[1]>M) tmp+=d[1]-M; //第一个敌人还没有进入射程
int i=2,ok=1;
while(i<=N) //枚举敌人
{
tmp+=m; //将上一个敌人射杀,需换弹
if(tmp>d[i])
{
ok=0;
break;
}
if(d[i]-tmp>M) //如果换弹后敌人仍未进入射程,则可以在敌人进入射程之前换弹
{
tmp-=m;
tmp+=d[i]-tmp-M; //等待敌人进入射程
}
i++;
}
if(ok==1) return 1;
return 0;
}
int main()
{
freopen("48.in","r",stdin);
//freopen("48.out","w",stdout);
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++)
scanf("%d",&d[i]);
int A=0,B=10000000,ans=0;
sort(d+1,d+1+N); //按敌人相对山头的距离由小到大排序
for(int i=0;i<40;i++) //二分猜答案
{
int m=(A+B)/2;
if(check(m)) A=m+1,ans=m;
else B=m-1;
}
printf("%d\n",ans);
return 0;
}