APIO2007 資料備份(貪心)

2021-05-27 13:49:39 字數 2663 閱讀 1198

題目描述 :

題目大意是,在一條直線上有n個點,我們要從中取出k對點(k*2<=n),點不能被重複取,每對點之間有乙個距離,求距離的最小和。

n不超過100000  k不超過 n div 2

容易證明,組成一對的兩個點一定 是相鄰的:

比如:                a-------------------------b

c-----------------------d

如果ab一對,cd一對,那還不如ac一對,bd一對;

很明顯,dp是o(nk)的  :f[ i,k]:=min(f[  i-1,k],f[ i-2,k-1]+w[ i-1,i ])

f[i,k]表示掃到第i-1到第i 這兩個點,取了k對的最優值。

tle是明顯的,可以考慮效率更高的貪心。

因為只能選相鄰的點,我們不如用n-1 個距離代替n個點。

這樣,每次貪心的選取最小距離。

但這明顯是錯的,比如:a------------------------b--------------c------d----------e------------------------f

1000                         10               1         10                100

如果我們直接貪心的選取了cd,那麼接下來就只能選ab或ef,這樣還不如選bc 和 ef

所以要對貪心進行修正,比如,我們在選了cd之後,刪除bc ,cd,de,然後構造 be=bc+de-cd=19,並新增進去:

a------------------------b------------------e------------------------f

1000                        19                         1000

這樣,當我們貪心選取be的時候,就等於把cd「還了回來」,並選取了bc和de兩段,等於說還是多選了一段

這樣,選一次就多選了一段,貪心選n次即可。

實現的時候,貪心取最小可以用堆(我的堆 寫醜了,其實用zkw線段樹更漂亮),刪除和新增需要有鍊錶輔助。

klog(n)的複雜度足夠了。

program lmd;

var pred,next,heap,link,dist:array[0..200000]of longint;

a:array[0..120000]of int64;

i,n,k,top,high:longint;

ans:int64;

procedure swap(x,y:longint);

var z:longint;

begin

link[heap[x]]:=y;

link[heap[y]]:=x;

z:=heap[x];heap[x]:=heap[y];heap[y]:=z;

end;

procedure up(k:longint);

begin

while (k<>1) and (a[heap[k shr 1]]>a[heap[k]]) do

begin

swap(k shr 1,k);

k:=k shr 1;

end;

end;

procedure down(k:longint);

var j:longint;

begin

while (heap[k shl 1]+heap[k shl 1+1]<>0) do

begin

j:=k shl 1;

if heap[j]=0 then j:=j+1;

if (a[heap[k shl 1+1]]0) then

j:=k shl 1+1;

if a[heap[j]]0)and(next[high]<>n+1) then

begin

del(pred[high]);

del(next[high]);

del(high);

a[high]:=a[pred[high]]+a[next[high]]-a[high];

a[pred[high]]:=maxlongint shr 2;

a[next[high]]:=maxlongint shr 2;

add(high);

pred[high]:=pred[pred[high]];

next[pred[high]]:=high;

next[high]:=next[next[high]];

pred[next[high]]:=high;

endelse

begin

del(high);

if pred[high]=0 then

begin

del(next[high]);

pred[next[next[high]]]:=0;

end;

if next[high]=n+1 then

begin

del(pred[high]);

next[pred[pred[high]]]:=n+1;

end;

end;

end;

write(ans);

close(input);close(output);

end.

題解 APIO2007 風鈴

你需要選乙個滿足下面兩個條件的風鈴 1 所有的玩具都在同一層 也就是說,每個玩具到天花板之間的杆的個數是一樣的 或至多相差一層。2 對於兩個相差一層的玩具,左邊的玩具比右邊的玩具要更靠下一點。風鈴可以按照下面的規則重新排列 任選一根杆,將杆兩頭的線 交換 也就是解開一根杆左右兩頭的線,然後將它們綁到...

題解 APIO2007 動物園

傳送門 對於這個題目很明顯的就是狀壓dp,不過,作為乙個不會狀壓dp的蒟蒻,考場讓只能根據大佬們的之前聊天和對狀壓dp的印象來瞎搞 狀態是這樣設計的 f i,j 表示轉移到從第i個位置出發的j表示五個的動物的狀態能使多少個小朋友滿意 s i,j 表示從i出發的5個位置中表示j的狀態使多少個小朋友滿意...

題解 APIO2007動物園

首先一眼感受到這題特別的性質 5個?這麼小的,感覺就像是狀壓。腦補了一下,如果沒有環的話應該很好做吧 有環怎麼辦?5真的很小的,隨便亂搞肯定也可以。那就放在外面暴力列舉吧。然後正解就出來了。然而這題題面真的有毒吧。說好的不能全部選走?我還多加了乙個維度,結果資料裡面允許全部取走 然後對於 5的點單獨...