动物园

分析

本题对于 \(n\)\(c\) 的范围都比较大,不好直接处理,但是每个人可以看到的围栏数量只有 \(5\) 我们可以从这里入手考虑

\(dp[i][s]\) 表示对于 \(i,i+1,i+2,i+3,i+4\)\(5\) 个围栏的动物情况为 \(s\) 时的最大开心人数

那么转移即为:

\[dp[i][s]= \max(dp[i-1][((s\&15)<<1)|1],dp[i-1][(s\&15)<<1])+sum[i][s] \]

其中 \(sum[i][s]\) 表示第 \(i,i+1,i+2,i+3,i+4\) 个围栏中动物情况为 \(s\) 的开心人数

\((s\&15)<<1|1\)\((s\&15)<<1\) 则表示第 \(i-1,i,i+1,i+2,i+3\) 个围栏中的动物情况

对于 \(sum\) 数组的处理,我们考虑题目中的条件:

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

那么我们可以在输入的时候处理出每个人对于某个围栏的喜爱情况,即为 \(dislike\)\(like\) , 其含义与 \(dp[i][s]\) 中的 \(s\) 的含义相同

我们可以枚举围栏中的动物情况 \(j\) ,则:

if((j&dislike)||(~j&like)) sum[i][j]++;

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
#include<queue>
#define ll long long

inline ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch))
	{
		x=(x<<1)+(x<<3)+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const ll maxn=5e4+10;
const ll maxm=1e4+10;
const ll inf=1e9+7;
ll n,c,ans;
ll E,F,L,X,Y;
ll sum[maxn][(1<<5)+10];
ll dp[maxm][(1<<5)+10];

int main(void)
{
	n=read(),c=read();
	
	for(int i=1;i<=c;i++)
	{
		E=read(),F=read(),L=read();
		ll dlik=0,lik=0;
	
		for(int j=1;j<=F;j++)
		{
			scanf("%lld",&X);
			X=(X-E+n)%n;
			dlik|=1<<X;
		}	
		for(int j=1;j<=L;j++)
		{
			scanf("%lld",&Y);
			Y=(Y-E+n)%n;
			lik|=1<<Y;
		}
		for(int j=0;j<(1<<5);j++)
		{
			if((j&dlik)||(~j&lik)) sum[E][j]++;
		}
	}
	
	for(int i=0;i<32;i++)
	{
		for(int j=0;j<32;j++) dp[0][j]=-inf;
		dp[0][i]=0;
		
		for(int j=1;j<=n;j++)
		{
			for(int k=0;k<32;k++)
			{
				dp[j][k]=std::max(dp[j-1][((k&15)<<1)|1],dp[j-1][(k&15)<<1])+sum[j][k];
			}
		}
		
		ans=std::max(ans,dp[n][i]);
	}
	
	printf("%lld\n",ans);
	
	return 0;
}
posted @ 2021-02-20 20:22  雾隐  阅读(48)  评论(0编辑  收藏  举报