题目: | 超级钢琴 | |
来源: | Noi 2010 day1 第二题 | |
题目大意: | N个数,求K个长度大于L小于R的序列(每个序列为连续数的和),且每个序列元素 不能完全相同,求最大值 | |
数据范围: | N<=500000,K<=500000 | |
样例: | 4 3 2 3 3 2 -6 8 | 11 |
做题思路: | 怎么说呢,rmq+堆(大牛教的)。 Rmq用来找区间最大,把它记录在堆中,然后求出以该最大为边界的序列权值和, 维护堆,并由此插入该最大删除后的次大,然后就去k个数呗,over 还有一个20分的代码,就是朴素的算出所有满足要求的序列和,然后排序,输出 有一个样例是K=1的,能不能动归10分呢? | |
知识点: | RMQ(st,线段树),堆,二分求次大 |
const
MaxN=500010;
type
node=record
start,l,r,hmax,val:longint;{<开始,结束端的左右边界,最大点,权值和>}
end;
var
n,le,re,k,heaptot:longint;
a,sum:array[0..MaxN] of longint;
f:array[0..MaxN,0..30] of longint;
heap:array[0..MaxN*2] of node;
ans:int64;
procedure init;
var
i:longint;
begin
read(n,k,le,re);
for i:=1 to n do
begin
read(a[i]);
sum[i]:=sum[i-1]+a[i];{<求从1开始的和>}
end;
end;
function max(x,y:longint):longint;
begin
if sum[x]>sum[y] then exit(x) elseexit(y);
end;
procedure st;{<rmq问题初始化>}
var
i,j,t:longint;
begin
for i:=1 to n do f[i,0]:=i;
t:=trunc(ln(n)/ln(2));
for j:=1 to t do
for i:=1 to n-(1 shl j)+1 do
f[i,j]:=max(f[i,j-1],f[i+(1 shl(j-1)),j-1]);
end;
procedure swap(var x,y:node);
var
tmp:node;
begin
tmp:=x; x:=y; y:=tmp;
end;
procedure up(now:longint);{<上调>}
begin
while now>1 do
if (heap[now].val>heap[now shr 1].val)then
begin
swap(heap[now],heap[now shr 1]);
now:=now shr 1;
end else exit;
end;
procedure down(now:longint);{<下调>}
var
tmp:longint;
begin
while now shl 1<=heaptot do
begin
if (now shl 1=heaptot) or (heap[now shl1].val>heap[(now shl 1)+1].val)
then tmp:=now shl 1 else tmp:=(now shl1)+1;
if heap[tmp].val>heap[now].val then
begin
swap(heap[tmp],heap[now]);
now:=tmp;
end
else exit;
end;
end;
procedureinsert(i,ll,rr:longint);{<插入堆>}
var
tmp:longint;
begin
if rr>n then rr:=n;{<超出最大右边界则修改右边界>}
inc(heaptot);
with heap[heaptot] do{<with,对记录型内直接操作>}
begin
start:=i; l:=ll; r:=rr;
tmp:=trunc(ln(r-l+1)/ln(2));{<st>}
hmax:=max(f[l,tmp],f[r-(1 shltmp)+1,tmp]);
val:=sum[hmax]-sum[start-1];
end;
up(heaptot);
end;
procedure main;
var
i,tstart,tl,tr,tmax:longint;
begin
heaptot:=0;
for i:=1 to n do{<以i为左边界插入>}
begin
if i+le-1>n then break;{<左边界到最大右边界的距离<le,说明不符合要求>}
insert(i,i+le-1,i+re-1);{<插入所有的最大>}
end;
for i:=1 to k do
begin
ans:=ans+heap[1].val;{<累加答案>}
with heap[1] do
begin
tstart:=start;
tl:=l;
tr:=r;
tmax:=hmax;
end;
heap[1]:=heap[heaptot];
dec(heaptot);
down(1);
if tmax>tl theninsert(tstart,tl,tmax-1);{<这个值插入后,修改其右边界,继续插入,导致次大>}
if tmax<tr theninsert(tstart,tmax+1,tr);
end;
end;
begin
assign(intput,'piano.in');reset(input);
assign(output,'piano.out');rewrite(output);
init;
st;
ans:=0;
main;
writeln(ans);
close(input);close(output);
end.
题目来源:
http://www.tyvj.cn:8080/Problem_Show.asp?id=1256