Miners
阿新 • • 發佈:2018-08-11
cstring 狀壓 %d pan [1] continue 不能 ++i miner
Miners
有三種食品,兩組礦工。礦工們根據最近三次過來的食品車產煤,產出煤的個數就是新過來的食品車,和前面兩輛車中,不同的食品車的個數。
現在你有一個長度為n的食品車序列,請合理分配它們給兩組礦工,使得產煤個數最大。
我會做IOI的題啦!
\(f[i][a][b][c][d]\)嗎,表示當前是第i輛車,第一組礦工的最近兩組車分別是a,b,第二組礦工的最近兩組車分別是c,d的最大產煤個數。那麽\(f[i][a][b][c][d]->f[i+1][b][cur][c][d], f[i+1][a][b][d][cur]\)。
exp*1:這種關於時間的狀壓dp,或許可以不用保存最開始的那個狀態(可能有點抽象。以本題舉個例子,就是不用保存礦工最近三頓吃了什麽,只用保存最近兩頓吃了什麽)
exp*2:dp要註意初始情況中不合法的情況!
#include <cstdio> #include <cstring> using namespace std; const int maxn=1e5+5; int n, j, now, ans, f[2][4][4][4][4]; char s[maxn]; int a[maxn]; int t[4]; int val(int a, int b, int c){ memset(t, 0, sizeof(t)); ++t[a]; ++t[b]; ++t[c]; return (bool)t[1]+(bool)t[2]+(bool)t[3]; } inline int max(int x, int y){ return x<y?y:x; } inline void up(int &x, int y){ if (y>x) x=y; } int main(){ scanf("%d%s", &n, s); for (int i=0; i<n; ++i){ if (s[i]=='M') a[i]=1; if (s[i]=='F') a[i]=2; if (s[i]=='B') a[i]=3; } memset(f, -1, sizeof(f)); f[0][0][0][0][0]=0; for (int i=0; i<=n; ++i){ now=a[i]; for (int a=0; a<4; ++a) for (int b=0; b<4; ++b) for (int c=0; c<4; ++c) for (int d=0; d<4; ++d){ if (f[j][a][b][c][d]==-1) continue; //這個狀態如果不行就不能轉移 up(f[j^1][b][now][c][d], f[j][a][b][c][d]+val(a, b, now)); up(f[j^1][a][b][d][now], f[j][a][b][c][d]+val(c, d, now)); ans=max(ans, f[j][a][b][c][d]); } memset(f[j], -1, sizeof(f[j])); j^=1; } printf("%d\n", ans); return 0; }
Miners