APIO2007 动物园

题目链接

Solution

(f_{i,S}) 表示前 (i) 个围栏,围栏 (i) 能看到的 (5) 个围栏状态为 (S) 时最多使多少小朋友开心。由于围栏 (i-1) 的视野与围栏 (i) 的视野只有 (1) 处不一致,得到转移方程:

     f[i][j] = max(f[i - 1][j & 15 < < 1] , f[i - 1][(( j & 15 ) << 1) | 1])

其中 (j & 15) << 1 表示取出 (j) 的后四位并左移

由于是一个环形,需要枚举开头的状态(即 (f_{0,S})(S)),结尾的状态必须与它一致

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
 
int n, c, e, fi, l, a, ans = 0, num[20000][100], f[20000][100];
 
int main()
{
    scanf("%d%d", &n, &c);
    for(int i = 1; i <= c; i++)
    {
        scanf("%d%d%d", &e, &fi, &l);
        int fear = 0, like = 0;
        for(int j = 1; j <= fi; j++)
        {
            scanf("%d", &a);
            a = (a - e + n) % n; fear |= (1 << a);
        }
	for(int j = 1; j <= l; j++)
        {
            scanf("%d", &a);
            a = (a - e + n) % n; like |= (1 << a);
        }
        for(int j = 0; j < 32; j++)
            num[e][j] += ((fear &(~j)) || (like & j));
    }
    for(int i = 0; i < 32; i++)
    {
        memset(f, -0x3f, sizeof(f)); f[0][i] = 0;
        for(int j = 1; j <= n; j++)
            for(int k = 0; k < 32; k++)
                f[j][k] = max(f[j - 1][(k & 15) << 1], f[j - 1][((k & 15) << 1) | 1]) + num[j][k];
        ans = max(ans, f[n][i]);
    }
    printf("%d", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Andy-park/p/12501992.html