Description
经过三十多个小时的长途跋涉,小Z和小D终于到了NOI现场——南山南中学。一进校园,小D就被花所吸引了(不要问我为什么),遍和一旁的种花园丁交(J)流(L)了起来。
他发现花的摆放竟有如此奥秘:圆形广场共有 NN 个种花的位置,顺时针编号到 N N。并且每个位置都有一个美观度aiai ,如果在这里种花就可以得到这 ai ai 的美观度。但由于地处南山土壤肥力欠佳,两株花不能种在相邻的位置( 1 1 号和 N N 号也算相邻位置)。校方一共给了 MM 株花,经过园丁的精妙摆放,才能如此吸引小D。所以现在小D也想知道应该如何摆这 株花。
Input
输入第一行包含两个整数 N,M N,M 。
接下来一行包含 N N 个正整数,依次描述美观度 a1,a2,...,an a1,a2,...,an。
Output
输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”“Error!”,不包含引号。
Data Constraint
对于 50% 50% 的数据满足 N<=3000 N<=3000。
对于 100% 100% 的数据满足 M<=N<=200000,−1000<=ai<=1000 M<=N<=200000,−1000<=ai<=1000。
Sample Input
7 3
1 2 3 4 5 6 7
Sample Output
15
Solution
贪心+堆。
以 Ai Ai 为关键字建大根堆,用一个链表存放当前物品。
最初链表中元素是 11~,i i 的后继是 i+1i+1,前驱是 i−1i−1(当然,11 的前驱是 ,NN 的后继是 )。
执行 MM 次操作,每一次操作都将堆顶元素 取出,ans+=Akans+=Ak。然后在链表中删除 kk 的前驱
和后继 nxtnxt,令 Ak=Apre+Anxt−AkAk=Apre+Anxt−Ak,并更新堆。
这样做的合理性:
保证了一段区间内的最优解,并增加了撤销性。
(笔者由于一时懵逼打了棵线段树,凑合着用吧)
Code
const maxn=200005;
var a:array[1..maxn] of int64;
suf,pre:array[1..maxn] of longint;
tree:array[1..5*maxn] of int64;
n,m,i:longint;
ans:int64;
function max(x,y:int64):int64;
begin if x>y then exit(x);exit(y);end;
procedure build(x,l,r:longint);
var mid:longint;
begin
if l=r then begin
tree[x]:=a[l];
exit;
end;
mid:=(l+r) div 2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
tree[x]:=max(tree[x*2],tree[x*2+1]);
end;
procedure kill(x,l,r,z:longint);
var mid:longint;
begin
if l=r then begin
tree[x]:=-maxlongint;
a[l]:=-maxlongint;
exit;
end;
mid:=(l+r) div 2;
if mid>=z then kill(x*2,l,mid,z) else
kill(x*2+1,mid+1,r,z);
tree[x]:=max(tree[x*2],tree[x*2+1]);
end;
procedure work(x,l,r:longint);
var mid:longint;
begin
if l=r then begin
ans:=ans+tree[x];
tree[x]:=a[pre[l]]+a[suf[l]]-a[l];
a[l]:=a[pre[l]]+a[suf[l]]-a[l];
kill(1,1,n,pre[l]);
kill(1,1,n,suf[l]);
pre[l]:=pre[pre[l]];
suf[pre[l]]:=l;
suf[l]:=suf[suf[l]];
pre[suf[l]]:=l;
exit;
end;
mid:=(l+r) div 2;
if tree[x*2]>=tree[x*2+1] then work(x*2,l,mid)
else work(x*2+1,mid+1,r);
tree[x]:=max(tree[x*2],tree[x*2+1]);
end;
begin
readln(n,m);
read(a[1]);
pre[1]:=n;
suf[1]:=2;
for i:=2 to n-1 do begin
read(a[i]);
pre[i]:=i-1;
suf[i]:=i+1;
end;
read(a[n]);
pre[n]:=n-1;
suf[n]:=1;
build(1,1,n);
if m>n div 2+n mod 2 then begin
writeln('Error!');
exit;
end;
for i:=1 to m do work(1,1,n);
writeln(ans);
end.