P2157 SDOI2009 學校食堂

2022-05-20 02:07:41 字數 1549 閱讀 5041

傳送門

做菜主要是按時間順序,所以可以考慮dp

但是可能後面的人會先打飯

可以發現同學最多只能讓後面的第7個同學先打飯

可以從這裡入手考慮問題

把每8個一起的同學看成乙個狀態

在他們之前的人都已經打好飯了

想象乙個從左往右的佇列

從1~i-1 的同學都打完飯了

然後需要知道的狀態是 i~i+7 共8個同學的總狀態

顯然如果第 i 個同學已經打好了

那麼 1~i 的同學都好了

所以可以轉到下乙個 i

設 f [ i ] [ j ] 表示從1~i-1 的同學都好了,第 i~i+7 的總狀態為 j 時需要的最少時間

那麼 如果 j&1 ==1 說明第 i 個同學已經好了

這時可以轉到 f[ i+1 ] [ j>>1 ] (顯然)

但是具體轉的時候發現:

不知道上乙個打飯的人是誰,就不知道這次需要多少時間...

但是可以發現

上乙個打飯的人肯定在 i-8 ~ i+7 之間(不然肯定有同學不能容忍了)

所以多開一維

設 f [ i ] [ j ] [ k ]   i 和 j 含義不變, k 表示上乙個打飯的人是 i + k (-8<=k<=7,存的時候要加8)

那麼 如果 j&1 ==1 f[ i ] [ j ] [ k ] 就可以轉到 f [ i+1 ] [ j>>1 ] [ k-1 ] (注意這時並沒有人打飯,只是兩個狀態表示的含義相同,可以直接轉移)

然後考慮給乙個人打飯

列舉 i ~ i+7 的人 h(h是與 i 的相對距離,和 k 一樣)

那麼 f [ i ] [ j ] [ k ] 可以轉到 f [ i ] [ j|(1<

並且增加的時間是 (a[ i+k ]|a[ i+h ]) - (a[ i+k ]&a[ i+h ])  =  a[ i+k ] ^ a[ i+h ]

注意判斷 h 的合法性

顯然乙個同學如果打過飯了就不能再打   (j&(1<

還要注意左邊同學的容忍度   (j&(1<

然後就可以轉移了

最後在 f [ n+1 ] [ 0 ] [ i ] 之間取 min 就好了

#include#include

#include

#include

#include

using

namespace

std;

const

int n=2007,inf=0x3f3f3f3f

;int

t,n,a[n],b[n];

int f[n][307][17

];inline

bool pd(int &i,int &j,int &h)//

判斷合法性

intmain()

}int ans=inf;

for(int i=0;i<16;i++) ans=min(ans,f[n+1][0

][i]);

printf(

"%d\n

",ans);

}return0;

}

P2157 SDOI2009 學校食堂

小f 的學校在城市的乙個偏僻角落,所有學生都只好在學校吃飯。學校有乙個食堂,雖然簡陋,但食堂大廚總能做出讓同學們滿意的菜餚。當然,不同的人口味也不一定相同,但每個人的口味都可以用乙個非負整數表示。由於人手不夠,食堂每次只能為乙個人做菜。做每道菜所需的時間是和前一道菜有關的,若前一道菜的對應的口味是a...

P2157 SDOI2009 學校食堂 狀壓DP

有點複雜,自行瀏覽吧 題目鏈結 我們發現dp轉移時需要記錄以下幾個資訊 打飯佇列的隊首是誰,上乙個打飯的是誰,佇列前b i b i b i 個人的狀態 然後我們根據這些資訊設立dp狀態,記f i j k f i j k f i j k 表示該第i ii個人打飯 等價於前i 1 i 1i 1個人已經買...

Luogu2157 SDOI2009 學校食堂

link 給定 n 個學生的口味和忍耐度,若前一道菜的對應的口味是a,這一道為b,則做這道菜所需的時間為 a b a b 而做第一道菜是不需要計算時間的.每個學生可以忍耐忍耐度以下的人在他前面插隊買飯 求最小的做飯時間 n le 1000,b i le 8 令 f 表示第 i 個人前面的狀態是 s ...