【注:欧少队列 == 单调队列】
题意:给定一个序列,要求从其中取出一些无交集的子段,使得子段长大于k且段中的最大值最小值之差不大于m,问最多能取出多少个。
单调队列题。考场没写出来。
标准做法是:维护最大值最小值和F[k] - k的单调队列。
XJJ的神级做法:直接记录每个点和前k-1个数的最大最小值,F记两维,f[0][k] 表示必须不取k的1~k的最优值,f[1][k]表示必须取k的1~k最优值。
然后就可以做了..跪。
最近又在写p了。嗯。为了联(bu)赛(luo)。
program gift;
const
maxn = 300005;
inf = 'gift.in';
ouf = 'gift.out';
var
i, k, n, m, t, head, tail : longint;
mx, mn : Array[0 .. maxn] of longint;
f : Array[0 .. 1, 0 .. maxn] of longint;
w, q : Array[0 .. maxn] of longint;
function min(a, b : longint) : longint; begin if a < b then exit(a) else exit(b); end;
function max(a, b : longint) : longint; begin if a > b then exit(a) else exit(b); end;
begin
assign(input, inf); reset(input);
assign(output, ouf); rewrite(output);
readln(t);
while t > 0 do begin
readln(n, m, k);
fillchar(f, sizeof(f), 0);
for i := 1 to n do read(w[i]);
mx[1] := w[1]; q[1] := 1;
head := 1; tail := 1;
for i := 2 to n do begin
while (tail >= head) and (w[i] > w[q[tail]]) do dec(tail);
inc(tail); q[tail] := i;
if (i - q[head] >= k) then inc(head);
mx[i] := w[q[head]];
end;
mn[1] := w[1]; q[1] := 1;
head := 1; tail := 1;
for i := 2 to n do begin
while (tail >= head) and (w[i] < w[q[tail]]) do dec(tail);
inc(tail); q[tail] := i;
if (i - q[head] >= k) then inc(head);
mn[i] := w[q[head]];
end;
for i := k to n do begin
f[0, i] := max(f[0, i - 1], f[1, i - 1]);
if (max(mx[i - 1], w[i]) - min(mn[i - 1], w[i]) <= m) then
f[1, i] := f[1, i - 1] + 1
else
f[1, i] := 0;
if (mx[i] - mn[i] <= m) then
f[1, i] := max(f[1, i], k + max(f[0, i - k], f[1, i - k]));
end;
writeln(max(f[1, n], f[0, n]));
dec(t);
end;
close(input); close(output);
end.