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.

 

你可能感兴趣的:(ZOJ)