您的位置:首页 > Web前端 > JavaScript

【BZOJ4476&JSOI2015】送礼物(二分,RMQ)

2015-12-03 21:03 603 查看

ANS明显是有二分性的

 

二分答案,设二分值为b
M(i,j)−m(i,j)j−i+k>b

显然当l<长度<r时,一端是最小值,一端是最大值。

等于l或r的时候因为可能不满足以上性质,所以RMQ暴力O(nlogn)做。 

a[i]−a[j]>b∗j−b∗i+b∗k 或 a[j]−a[i]>b∗j−b∗i+b∗k
那么
(a[i]+b∗i)−(a[j]+b∗j)>b∗k 或 (−a[i]+b∗i)−(−a[j]+b∗j)>b∗k

 

是一个单调队列的样子

 

var f1,f2:array[1..60000,0..20]of extended;
q:array[1..200000]of longint;
a,e:array[0..200000]of extended;
mi:array[0..30]of int64;
log:array[1..2000000]of longint;
cas,i,v,j:longint;
n,l1,r1,lg:int64;
l,r,mid,k:extended;

function max(x,y:extended):extended;
begin
if x>y then exit(x);
exit(y);
end;

function min(x,y:extended):extended;
begin
if x<y then exit(x);
exit(y);
end;

function querymin(x,y:longint):extended;
var len:longint;
begin
len:=log[y-x+1];
exit(min(f1[x,len],f1[y-mi[len]+1,len]));
end;

function querymax(x,y:longint):extended;
var len:longint;
begin
len:=log[y-x+1];
exit(max(f2[x,len],f2[y-mi[len]+1,len]));
end;

procedure build1;
var i,j:longint;
begin
for i:=1 to lg do
for j:=1 to n-mi[i]+1 do f1[j,i]:=min(f1[j,i-1],f1[j+mi[i-1],i-1]);
end;

procedure build2;
var i,j:longint;
begin
for i:=1 to lg do
for j:=1 to n-mi[i]+1 do f2[j,i]:=max(f2[j,i-1],f2[j+mi[i-1],i-1]);
end;

function isok(b:extended):boolean;
var h,w,i:longint;
begin
for i:=1 to n do e[i]:=a[i]+b*i;
h:=1; w:=1;
q[1]:=n;
for i:=n-l1+1 downto 1 do
begin
while (h<=w)and(q[h]>i+r1-1) do inc(h);
if e[i]-e[q[h]]>=b*k then exit(true);
while (h<=w)and(e[q[w]]>=e[i+l1-2]) do dec(w);
inc(w); q[w]:=i+l1-2;
end;
for i:=1 to n do e[i]:=-a[i]+b*i;
h:=1; w:=1;
q[1]:=n;
for i:=n-l1+1 downto 1 do
begin
while (h<=w)and(q[h]>i+r1-1) do inc(h);
if e[i]-e[q[h]]>=b*k then exit(true);
while (h<=w)and(e[q[w]]>=e[i+l1-2]) do dec(w);
inc(w); q[w]:=i+l1-2;
end;
exit(false);
end;

begin
assign(input,'gift.in'); reset(input);
assign(output,'gift.out'); rewrite(output);
readln(cas);
mi[0]:=1;
for i:=1 to 20 do mi[i]:=mi[i-1]*2;
for i:=0 to 19 do
for j:=mi[i] to mi[i+1]-1 do log[j]:=i;
for v:=1 to cas do
begin
readln(n,k,l1,r1);
for i:=1 to n do read(a[i]);
l:=0; r:=1000;
for i:=1 to n do
begin
f1[i,0]:=a[i];
f2[i,0]:=a[i];
end;
lg:=log[r1];
build1; build2;
for i:=1 to n-l1+1 do l:=max(l,(querymax(i,i+l1-1)-querymin(i,i+l1-1))/(l1-1+k));
for i:=1 to n-r1+1 do l:=max(l,(querymax(i,i+r1-1)-querymin(i,i+r1-1))/(r1-1+k));
l1:=l1+1; r1:=r1-1;
if l1<=r1 then
while r-l>1e-6 do
begin
mid:=(r+l)/2;
if isok(mid) then l:=mid
else r:=mid;
end;
writeln(l:0:4);
end;
close(input);
close(output);
end.

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: