[BZOJ1151] 动物园

问题描述

新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一
种动物。你是动物园的公共主管。你要做的是,让每个来动物园的人都尽可能高兴。今天有一群小朋友来动物园参观,你希望能让他们在动物园度过一段美好的时光。但这并不是一件容易的事——有的动物有一些小朋友喜欢,有的动物有一些小朋友害怕。如,Alex 喜欢可爱的猴子和考拉,而害怕拥牙齿锋利的狮子。而Polly 会因狮子有美丽的鬃毛而喜欢它,但害怕有臭味的考拉。你可以选择将一些动物从围栏中移走以使得小朋友不会害怕。但你不能移走所有的动物,否则小朋友们就没有动物可看了。每个小朋友站在大围栏圈的外面,可以看到连续的 5 个围栏。你得到了所有小朋友喜欢和害怕的动物信息。当下面两处情况之一发生时,小朋友就会高兴:

  • 至少有一个他害怕的动物被移走
  • 至少有一个他喜欢的动物没被移走

输入格式

输入的第一行包含两个整数N, C,用空格分隔。

N是围栏数(10≤N≤10 000),C是小朋友的个数(1≤C≤50 000)。

围栏按照顺时针的方向编号为1,2,3,…,N。

接下来的C行,每行描述一个小朋友的信息,以下面的形式给出: E F L X1 X2 … XF Y1 Y2 … YL

其中: E表示这个小朋友可以看到的第一个围栏的编号(1≤E≤N),

换句话说,该小朋友可以看到的围栏为E, E+1, E+2, E+3, E+4。

注意,如果编号超过N将继续从1开始算。

如:当N=14, E=13时,这个小朋友可以看到的围栏为13,14,1, 2和3。

F表示该小朋友害怕的动物数。

L表示该小朋友喜欢的动物数。

围栏X1, X2, …, XF 中包含该小朋友害怕的动物。

围栏Y1, Y2, …, YL 中包含该小朋友喜欢的动物。

X1, X2, …, XF, Y1, Y2, …, YL是两两不同的整数,

而且所表示的围栏都是该小朋友可以看到的。

小朋友已经按照他们可以看到的第一个围栏的编号从小到大的顺序排好了

(这样最小的E对应的小朋友排在第一个,最大的E对应的小朋友排在最后一个)。

注意可能有多于一个小朋友对应的E是相同的。

输出格式

仅输出一个数,表示最多可以让多少个小朋友高兴

样例输入

10 10
1 1 1 3 2
2 1 0 4
3 1 1 5 6
4 1 1 7 6
5 1 0 6
6 1 2 9 8 10
7 1 0 10
8 1 0 8
9 1 1 1 2
10 1 0 2

样例输出

10

解析

每一个小朋友只关心以他为起点的5个格子,若将移除即为0,不移走记为1,我们就可以用5位2进制数来表示下5个位置(i,i+1,i+2,i+3,i+4)的状态。如何在已知区间状态的情况下,判断小朋友是否开心?同样,将喜欢的动物压缩成二进制数p1,记该区间状态为s,如果s&p1不为0,说明有喜欢的动物没有被删。将不喜欢的动物压缩成二进制数p2,如果s&p2不等于p2,说明不喜欢的都没有出现。由此,可以设\(g[i][j]\)表示在i点时后面5格状态为j时i点有多少小朋友开心,预处理一下。

接下来进行DP。首先处理环的问题,为保证第n个与第1~4的状态相符,可以枚举确认前4为的情况s0,然后设初始状态\(f[0][s0]=0\),其余均为负无穷。对于i的状态j,i-1的状态只可能为j>>1或j>>1+1<<4(即第i-1个动物是否被移走),状态转移方程为

\[f[i][j]=max(f[i-1][j>>1],f[i-1][j>>1+1<<4])+g[i][j] \]

最后答案为

\[ans=max(f[n][s0],f[n][s0+1<<4]) \]

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#define N 50002
#define M 10002
using namespace std;
int n,c,i,j,s,e,a,b,f[M][1<<6],g[M][1<<6],ans;
int main()
{
	cin>>n>>c;
	for(i=1;i<=c;i++){
		int x,tmp1=0,tmp2=0;
		cin>>e>>a>>b;
		for(j=1;j<=a;j++){
			cin>>x;
			tmp1|=(1<<(4-(x-e+n)%n));
		}
		for(j=1;j<=b;j++){
			cin>>x;
			tmp2|=(1<<(4-(x-e+n)%n));
		}
		for(j=0;j<(1<<5);j++){
			if((j&tmp1)||(j&tmp2)!=tmp2) g[e][j]++;
		}
	}
	for(s=0;s<(1<<4);s++){
		memset(f[0],0xcf,sizeof(f[0]));
		f[0][s]=0;
		for(i=1;i<=n;i++){
			for(j=0;j<(1<<5);j++){
				f[i][j]=max(f[i-1][j>>1],f[i-1][(j>>1)+(1<<4)])+g[i][j];
			}
		}
		ans=max(ans,max(f[n][s],f[n][s+(1<<4)]));
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2019-08-30 21:59  CJlzf  阅读(168)  评论(0编辑  收藏  举报