1112: [POI2008]砖块Klo

时间:2023-03-09 06:56:32
1112: [POI2008]砖块Klo

1112: [POI2008]砖块Klo

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1245  Solved: 426
[Submit][Status][Discuss]

Description

N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

Input

第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

Output

最小的动作次数

Sample Input

5 3
3
9
2
3
1

Sample Output

2

HINT

原题还要求输出结束状态时,每柱砖的高度.本题略去.

Source

题解:(呵呵呵我会说我逗到了用Splay做这题的地步么= =)

首先,看这道题,对于某个高度序列而言,很明显将所有高度都变为中位数代价最小

我觉得任何一个数竞党都该知道怎么样可以让下列式子值最小——

\( \sum_{i=1}^{N} \left | x-x_i \right | \)
其中,\( x_1 \leq x_2 \leq x_3 ... \leq x_N \)
显然,当N为奇数时, \( x=x_\frac{N+1}{2} \)
当N为偶数时, \( x_\frac{N}{2} \leq x \leq x_\frac{N+2}{2} \)

然后接下来讨论怎么实现——我们需要一棵平衡树,可以加入和删除值,可以查询指定排名的数位置(用来找中位数),还得可以快速求出当前序列中比中位数大的各个数之和,以及比它小的之和,这样子就很明显需要维护子树大小(用于排名),然后还得维护子树和,然后我为了偷懒就直接来了个splay,每次将中位数splay上来,然后两边的不就是我们要的两边和嘛,然后该怎么办怎么办,别的没了

 /**************************************************************
Problem:
User: HansBug
Language: Pascal
Result: Accepted
Time: ms
Memory: kb
****************************************************************/ var
i,j,k,m,n,head:longint;
l,ans:int64;
lef,rig,b:array[..] of longint;
a,c:array[..] of int64;
procedure rt(var x:longint);inline;
var f,l:longint;
begin
if (x=) or (lef[x]=) then exit;
b[lef[x]]:=b[x];b[x]:=b[rig[lef[x]]]+b[rig[x]]+;
c[lef[x]]:=c[x];c[x]:=c[rig[lef[x]]]+c[rig[x]]+a[x];
f:=x;l:=lef[x];
lef[f]:=rig[l];
rig[l]:=f;
x:=l;
end;
procedure lt(var x:longint);inline;
var f,r:longint;
begin
if (x=) or (rig[x]=) then exit;
b[rig[x]]:=b[x];b[x]:=b[lef[rig[x]]]+b[lef[x]]+;
c[rig[x]]:=c[x];c[x]:=c[lef[rig[x]]]+c[lef[x]]+a[x];
f:=x;r:=rig[x];
rig[f]:=lef[r];
lef[r]:=f;
x:=r;
end;
procedure splay(var x:longint;y:longint);inline;
begin
if (x=) or (y=) then exit;
if y=(b[lef[x]]+) then exit;
if y<(b[lef[x]]+) then
begin
if (b[lef[lef[x]]]+)=y then rt(x) else
if y<(b[lef[lef[x]]]+) then
begin
splay(lef[lef[x]],y);
rt(x);rt(x);
end
else
begin
splay(rig[lef[x]],y-b[lef[lef[x]]]-);
lt(lef[x]);rt(x);
end;
end
else
begin
y:=y--b[lef[x]];
if y=(b[lef[rig[x]]]+) then lt(x) else
if y<(b[lef[rig[x]]]+) then
begin
splay(lef[rig[x]],y);
rt(rig[x]);lt(x);
end
else
begin
splay(rig[rig[x]],y--b[lef[rig[x]]]);
lt(x);lt(x);
end;
end;
end;
procedure ins(var x:longint;y:longint);inline;
begin
if x= then
begin
x:=y;
exit;
end;
if a[y]<=a[x] then
begin
ins(lef[x],y);
c[x]:=c[lef[x]]+c[rig[x]]+a[x];
b[x]:=b[lef[x]]+b[rig[x]]+;
end
else
begin
ins(rig[x],y);
c[x]:=c[lef[x]]+c[rig[x]]+a[x];
b[x]:=b[lef[x]]+b[rig[x]]+;
end;
end;
function getrank(x,y:longint):longint;inline;
begin
if x= then exit(-);
if a[x]=y then exit(b[lef[x]]+);
if y<a[x] then exit(getrank(lef[x],y)) else exit(b[lef[x]]++getrank(rig[x],y));
end;
procedure init(x:longint);inline;
begin
ins(head,x);
splay(head,random(b[head])+);
end;
procedure kill(x:longint);inline;
begin
if x= then
begin
splay(head,);
dec(c[head],c[lef[head]]);
dec(b[head]);
lef[head]:=;
end
else if x=b[head] then
begin
splay(head,b[head]-);
dec(c[head],c[rig[head]]);
dec(b[head]);
rig[head]:=;
end
else begin
splay(head,x+);
splay(lef[head],x-);
dec(c[head],c[rig[lef[head]]]);dec(b[head]);
dec(c[lef[head]],c[rig[lef[head]]]);dec(b[lef[head]]);
rig[lef[head]]:=;
end;
end;
begin
readln(n,m);randomize;
if m<= then
begin
writeln();
halt;
end;
for i:= to n do
begin
readln(a[i]);
c[i]:=a[i];b[i]:=;
lef[i]:=;rig[i]:=;
end;
head:=;ans:=maxlongint*maxlongint;
for i:= to m do init(i);
for i:= to n-m+ do
begin
splay(head,(m+) div );
l:=;
if lef[head]<> then inc(l,a[head]*b[lef[head]]-c[lef[head]]);
if rig[head]<> then inc(l,c[rig[head]]-a[head]*b[rig[head]]);
if l<ans then ans:=l;
if i=(n-m+) then break;
kill(getrank(head,a[i]));
init(i+m);
end;
writeln(ans);
readln;
end.