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;
}
posted @ 2020-03-16 09:49  Nyxia  阅读(65)  评论(0编辑  收藏  举报