动物园
分析
本题对于 \(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;
}