1. 程式人生 > >Miners

Miners

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