山头狙击战battle.pas
【问题描述】
Lucky为了掩护大部队,单枪匹马同敌人周旋,后来被敌人包围在某山头……等等,为什么怎么听怎么像狼牙山五壮士!不过不用着急,这次Lucky携带了足够的弹药,完全可以将涌上来的敌人一个一个干掉。Lucky是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑和面子问题,Lucky会等待敌人靠近然后射击。
正当Lucky为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花k秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时Lucky无法将他击毙,那么我们可怜的Lucky就将牺牲在敌人的刺刀下。现在Lucky用心灵感应向你发出求助:要保住自己的性命并且歼灭所有敌人,Lucky最多只能用多少时间给枪装上一发子弹?
说明:假设一开始Lucky的枪中就有一发子弹,并且一旦确定一个装弹时间,Lucky始终会用这个时间完成子弹的装卸。希望你能帮助Lucky脱离险境。
【输入格式】battle.in
针对每组输入数据,第一行有两个整数n和m,(2≤n≤100,000; 1≤m≤10,000,000)n代表敌人个数,m代表Lucky的射程。
接下来有n行,每行一个整数mi,(1≤mi≤10,000,000),代表每个敌人一开始相对山头的距离(单位为米)。
【输出格式】battle.out
每组输出数据仅有一个整数,代表Lucky的换弹时间(单位为秒)。
【样例输入】
6 100
236
120
120
120
120
120
【样例输出】
25
【问题分析】
先来搞清一个问题:当装弹时间越短,可能消灭的敌人越多;装弹时间越长,可能消灭的敌人越少,这样随着装弹时间由短变长时,消来的敌人可能越来越少(也许不会变化,但至少不会增加的)。这样就可以满足一个递增变化的规律,我们可以先确定装弹时间的变化范围,然后使用二分这段时间来找到最合适的装弹时间。
(1)首先要对所有的敌人按从近到远进行排序,打击敌人也是按这个顺序打的;
(2)最短装弹时间显然为L=0(即无需等待,连发!),最长的第二近的敌人到达的时间(因为第一个无需装弹)R=a[2]。
(3)二分得装弹时间m,然后用这个装弹时间来检查所有的敌人是否能被消灭,若不能消灭表示装弹时间过长,则r :=m-1; 否则尝试用更长一点的装弹时间来检查是否能消灭敌人,即L := m + 1;
主要部分代码如下:
function check(x : longint) : boolean;
var
i : longint;
mark : boolean;
begin
mark := true;
s := 0; //用来表示射击第i个敌人时,已经消耗的时间
for i := 1 to n do begin
if d[i] - s > m then s := d[i] – m //当第i个敌人还未移动到射程范围
else if d[i] < s then begin //若第i个敌人已经越过射手,则射手死
mark := false; break;
end;
inc(s, x);
end;
chekc := mark;
end;
begin
readln(n, m);
for i := 1 to n do read(d[i]); readln;
Qsort(1, n);
L := 0; R := d[2];
While L <= R do begin
time :=(L + R) shr 1;
If check(time) then L := time + 1 else R := time – 1;
End;
If not check(time) then dec(time);
Writeln(time);
End.