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;
}