傳送門
做菜主要是按時間順序,所以可以考慮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 ...