bzoj 1150 贪心

  

  首先选取的线段一定是相邻两个端点线段,那么我们贪心的考虑这个问题,我们先在这n-1条线段中选出最短的一条,然后将这条线段的值改为左面的线段的值+右面的线段的值-自己的值,用这条线段取代原来这三条线段,继续做,那么这个取m次出来之后的就是答案,对于证明,我们可以大概的去想,选了新的线段代表不选这条原本的线段,然后选另两条相邻的线段,这样选的线段的条数只是+1,相当于又取了一条线段,正确性的证明可以大概感知。

  至于选最小的用堆来维护就行了,因为需要删除精确到点编号,对堆用的不熟悉,所以用sbt代替。

/**************************************************************
    Problem: 1150
    User: BLADEVIL
    Language: Pascal
    Result: Accepted
    Time:2708 ms
    Memory:11956 kb
****************************************************************/
 
//By BLADEVIL
type
    pointer=^rec;
    rec                     =record
        pred, succ          :pointer;
        num, fuck           :int64;
    end;
    shit                    =record
        shit1, shit2        :longint;
    end;
     
var
    n, m                    :longint;
    a                       :array[0..200100] of pointer;
    left, right, size       :array[0..400100] of longint;
    key, adr                :array[0..400100] of longint;
    t, tot                  :longint;
    ans                     :int64;
     
procedure left_rotate(var t:longint);
var
    k                       :longint;
begin
    k:=right[t];
    right[t]:=left[k];
    left[k]:=t;
    size[k]:=size[t];
    size[t]:=size[left[t]]+size[right[t]]+1;
    t:=k;
end;
 
procedure right_rotate(var t:longint);
var
    k                       :longint;
begin
    k:=left[t];
    left[t]:=right[k];
    right[k]:=t;
    size[k]:=size[t];
    size[t]:=size[left[t]]+size[right[t]]+1;
    t:=k;
end;
 
procedure maintain(var t:longint;flag:boolean);
begin
    if not flag then
    begin
        if size[left[left[t]]]>size[right[t]] then
            right_rotate(t) else
        if size[right[left[t]]]>size[right[t]] then
        begin
            left_rotate(left[t]);
            right_rotate(t);
        end else exit;
    end else
    begin
        if size[right[right[t]]]>size[left[t]] then
            left_rotate(t) else
        if size[left[right[t]]]>size[left[t]] then
        begin
            right_rotate(right[t]);
            left_rotate(t);
        end else exit;
    end;
    maintain(left[t],false);
    maintain(right[t],true);
    maintain(t,true);
    maintain(t,false);
end;
     
procedure insert(var t:longint;v,k:int64);
begin
    if t=0 then
    begin
        inc(tot);
        t:=tot;
        left[t]:=0;
        right[t]:=0;
        size[t]:=1;
        key[t]:=v;
        adr[t]:=k;
    end else
    begin
        inc(size[t]);
        if v<key[t] then insert(left[t],v,k) else
        if v>key[t] then insert(right[t],v,k) else
        if v=key[t] then
            if k>adr[t] then insert(right[t],v,k) else
                insert(left[t],v,k);
        maintain(t,v>=key[t]);
    end;
end;
 
function delete(var t:longint;v,k:int64):shit;
var
    damn                    :shit;
begin
    dec(size[t]);
    if (v=key[t]) and (k=adr[t]) or (v>key[t]) and (right[t]=0) or (v<key[t]) and (left[t]=0) then
    begin
        delete.shit1:=key[t];
        delete.shit2:=adr[t];
        if (left[t]=0) or (right[t]=0) then
            t:=left[t]+right[t] else
            begin
                damn:=delete(left[t],v+1,k);
                key[t]:=damn.shit1;
                adr[t]:=damn.shit2;
            end;
    end else
        if v<key[t] then delete:=delete(left[t],v,k) else
        if v>key[t] then delete:=delete(right[t],v,k) else
            if v=key[t] then
                if k>adr[t] then delete:=delete(right[t],v,k) else
                if k<adr[t] then delete:=delete(left[t],v,k);
end;
 
function mini(var t:longint):longint;
begin
    if left[t]=0 then exit(adr[t]) else exit(mini(left[t]));
end;
     
procedure init;
var
    i                       :longint;
    null                    :pointer;
     
begin
    read(n,m);
    for i:=1 to n do
    begin
        new(null);
        a[i]:=null;
        read(a[i]^.num);
    end;
    for i:=n downto 2 do a[i]^.num:=a[i]^.num-a[i-1]^.num;
    a[1]^.num:=10000000000;
    for i:=1 to n do
    begin
        if i=1 then a[i]^.pred:=a[n] else a[i]^.pred:=a[i-1];
        if i=n then a[i]^.succ:=a[1] else a[i]^.succ:=a[i+1];
    end;
    for i:=1 to n do a[i]^.fuck:=i;
end;
 
procedure main;
var
    i                       :longint;
    x                       :longint;
begin
    t:=0;
    for i:=1 to n do insert(t,a[i]^.num,i);
    for i:=1 to m do
    begin
        x:=mini(t);
        ans:=ans+a[x]^.num;
        delete(t,a[x]^.num,a[x]^.fuck);
        delete(t,a[x]^.pred^.num,a[x]^.pred^.fuck);
        delete(t,a[x]^.succ^.num,a[x]^.succ^.fuck);
        a[x]^.num:=a[x]^.pred^.num+a[x]^.succ^.num-a[x]^.num;
        insert(t,a[x]^.num,x);
        a[x]^.pred^.pred^.succ:=a[x];
        a[x]^.pred:=a[x]^.pred^.pred;
        a[x]^.succ^.succ^.pred:=a[x];
        a[x]^.succ:=a[x]^.succ^.succ;
    end;
    writeln(ans);
end;
 
begin
    init;
    main;
end.

 

posted on 2014-01-20 16:47  BLADEVIL  阅读(660)  评论(0编辑  收藏  举报