[jzoj]3521.道路覆蓋(cover)


Link

  https://jzoj.net/senior/#main/show/3521

Description

  Tar把一段凹凸不平的路分成了高度不同的N段,並用H[i]表示第i段高度。現在Tar一共有n種泥土可用,它們都能覆蓋給定的連續的k個部分。對於第i種泥土,它的價格為C[i],可以使得區間[i,min(n,i+k-1)] 的路段的高度增加E[i]。Tar要設定一種泥土使用計划,使得使用若干泥土后,這條路最低的高度盡量高,並且這個計划必須滿足以下兩點要求:
  (1)每種泥土只能使用一次。
  (2)泥土使用成本必須小於等於M。
  請求出這個最低的高度最高是多少。

Solution

30分

  事實上,數據是允許拿到90分的,我們直接跑一次遞歸就可以了,記錄最低值的最高值

100分

  這個的狀壓DP很巧妙,從來沒做過這種不需要存所有狀態的狀壓DP

  從“最低的高度最高”就可以看出,這道題是用二分的,正解就是二分答案。

  從而,我們就把這道題目變為一道判定性的問題,給出一個mid,問你是否符合上面的題意。

  普通方法使用遞歸判斷可行性

  既然可以用遞歸,那么顯然可以用動態規划。

  我們設F[i,s]表示你當前想選第i種泥土,前面k種的狀態(包括i)是什么,用二進制表示,,0表示在那個位置沒用了泥土,1表示用了。(用沒用表示從他開始往后鋪,專屬於他的泥土)一定要看下面第二個圖

  我們用當前F[i,s]去更新F[i+1,s1]

  關鍵是我們怎么轉移。

  對於每一種泥土,只有選和不選兩種狀態,那么我們只要考慮這兩種情況就可以了

  在此之前,我們先看一個東西

  

 

  注意,我們這里是用i,更新i+1

  讀圖可以發現,對i+1有影響的只有從i前k-1個(包括i)

  可以發現,只有i包括i的前k-1個對i+1是有影響的。

  因為你選到i時,狀態是s,那么,如果從i更新到i+1,狀態就是s去掉最后一位,也就是(s>>1),其實就是s/2

  我們統計s狀態中,有哪個地方是選了泥土的,然后記錄一下,他們一共會讓i+1這個位置的土地高多少,設這個數為num,要多看圖,多寫草稿

  為什么呢,因為前面的加了對應的e數組的某一個值,又因為它會影響到當前這個位置,看上圖,所以,我們要看看,他們究竟影響到i+1這個位置增加多少值,所以我們要提前記錄下來

  其中S是枚舉的!枚舉的!枚舉的!

  

  ①不選

  如果不選,那么num+h[i]必定是大於等於mid的,這樣才符合題目要求,如果不懂反復讀上面的那句話,看看我畫出來精美的圖,就知道了。不懂都會懂

  滿足的上面的情況,我們就可以轉移了

  f[i+1,s>>1]:=min(f[i+1,s>>1],f[i,s]) 

  ②選

  如果選,就要滿足num+h[i]+E[i]是大於等於mid的,同理也是上面所說

  那么當前的位置s狀態中i+1的位置應該是1,所以,我們就是要更新新的s

  f[i+1,s>>1 or 1 shl (k-1)]:=min(f[i+1,s>>1 or 1 shl (k-1)],f[i,j]+c[i]);

  最后答案的判斷就是判斷有沒有一個被更改過值得f[n,i](i是狀態)是小於等於m的,因為在前面的操作中,都保證了更新過的f數組是符合題目要求的

  這道題充分的體現了動態規划的屌

Code

uses math;
var
        n,m,k,i,j,l,r,mid:longint;
        a,b,c:array[0..100] of longint;
        f:array[0..100,0..2047] of longint;
function pd(x:longint):boolean;
var
        i,j,jj,num:longint;
begin
        fillchar(f,sizeof(f),255);

        f[0,0]:=0;

        for i:=0 to n-1 do
        begin
                for j:=0 to 1 shl k-1 do
                        if f[i,j]<>-1 then
                        begin
                                num:=0;
                                for jj:=k-1 downto 1 do
                                        if (1 shl(jj)) and j<>0 then
                                                inc(num,b[i-(k-jj-1)]);

                                if num+a[i+1]>=x then
                                    if f[i+1,j shr 1]<>-1 then
                                        f[i+1,j shr 1]:=min(f[i+1,j shr 1],f[i,j])
                                    else
                                        f[i+1,j shr 1]:=f[i,j];

                                if num+a[i+1]+b[i+1]>=x then
                                    if f[i+1,j shr 1+1 shl (k-1)]<>-1 then
                                        f[i+1,j shr 1+1 shl (k-1)]:=min(f[i+1,j shr 1+1 shl (k-1)],f[i,j]+c[i+1])
                                    else
                                        f[i+1,j shr 1+1 shl (k-1)]:=f[i,j]+c[i+1];
                        end;
        end;

        for i:=0 to 1 shl k-1 do
                if f[n,i]<>-1 then
                        if f[n,i]<=m then
                                exit(true);

        exit(false);

end;
begin
        assign(input,'cover.in');reset(input);
        assign(output,'cover.out');rewrite(output);
        readln(n,m,k);
        for i:=1 to n do
                readln(a[i],b[i],c[i]);

        l:=1;
        r:=maxlongint-1;
        while l<=r do
        begin
                mid:=(l+r) shr 1;

                if pd(mid) then
                        l:=mid+1
                else
                        r:=mid-1;
        end;

        writeln(l-1);
end.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM