1. 程式人生 > >【BZOJ1806】礦工配餐

【BZOJ1806】礦工配餐

題目連結:https://www.lydsy.com/JudgeOnline/problem.php?id=1806


 

也是一道不錯的題目呢!BZOJ上面的題的確很好呢,可惜我到現在才開始刷。不可以再把暴力+騙分儘量拿省一然後就投入文化課作為目標了,一是因為運氣不一定那麼好,二是我又重新發現了OI的美。如果這次可以拿到省一,我決定和之前那位大神一樣,停課準備省選,哪怕這很難。

此題又涉及DP狀態設計的另一個技巧,或者說要求,當發現目前的狀態無法進行轉移,即缺少轉移所必要的條件時,就可以增加狀態的維數,記錄更多的資訊。一開始,我們可以設dp[i]表示考慮完第i輛車最大的產煤量,顯然無法進行轉移,因為對於第i+1輛車,我們不知道他去哪個礦會提供多少價值,因此我們可以將狀態改為dp[i][a][b][c][d]表示考慮完第i輛車,1號礦(假設的)的倒數第2輛為a,倒數第1輛為b,2號礦則分別是c和d,設第i輛車為food,則有dp[i][b][food][c][d]=max(dp[i][b][food][c][d],dp[i-1][a][b][c][d]+cnt)和dp[i][a][b][d][food]=max(dp[i][a][b][d][food],dp[i-1][a][b][c][d]+cnt),也就是分別討論第i輛車去哪個礦,其中cnt是第i輛車帶來的價值。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 const int maxn = 1e5 + 5;
 8 
 9 int dp[2][4][4][4][4];
10 char s[maxn];
11 
12 inline int diff(int a, int b, int f) {
13     int cnt = 1;
14     if (a != 0
&& a != b && a != f) ++cnt; 15 if (b != 0 && b != f) ++cnt; 16 return cnt; 17 } 18 19 int main() { 20 int n, food, ans = 0; 21 scanf("%d%s", &n, s + 1); 22 memset(dp, -1, sizeof(dp)); 23 dp[0][0][0][0][0] = 0; 24 for (int i = 1; i <= n; ++i) {
25 if (s[i] == 'M') food = 1; 26 else if (s[i] == 'F') food = 2; 27 else food = 3; 28 for (int a = 0; a <= 3; ++a) 29 for (int b = 0; b <= 3; ++b) 30 for (int c = 0; c <= 3; ++c) 31 for (int d = 0; d <= 3; ++d) { 32 if (dp[(i - 1) % 2][a][b][c][d] == -1) continue; 33 int cnt = diff(a, b, food); 34 dp[i % 2][b][food][c][d] = max(dp[i % 2][b][food][c][d], dp[(i - 1) % 2][a][b][c][d] + cnt); 35 cnt = diff(c, d, food); 36 dp[i % 2][a][b][d][food] = max(dp[i % 2][a][b][d][food], dp[(i - 1) % 2][a][b][c][d] + cnt); 37 if (i == n) ans = max(ans, max(dp[i % 2][b][food][c][d], dp[i % 2][a][b][d][food])); 38 } 39 } 40 printf("%d", ans); 41 return 0; 42 }
AC程式碼