P3622 [APIO2007]动物园
题目
给定一个有\(n\)个动物的环,你可以移除某些动物,有\(c\)个小朋友,每个小朋友能看到\(5\)个动物,每个小朋友有喜欢的和不喜欢的动物
定义小朋友高兴为
- 至少看到他喜欢的一个动物
- 至少有一个他不喜欢的动物被移除
问最多有多少小朋友高兴
\(10\le n \le10^4,1\le c\le5*10^5\)
思路
每个人只能看到\(5\)个动物而且每种动物只有\(0/1\)两种状态,这提示我们使用状压来做
不妨先考虑环的问题,显然可以每\(5\)个划分状态
设\(f[i][s]\)表示从到\(i\)且\([i,i+5)\)这几个动物的状态为\(s\)时最多能使多少小朋友开心
\(f[i][s]=\max(f[i-1][(s\&15)<<1],f[i-1][(s\&15)<<1|1])+sum[i][s]\)
\(sum[i][s]\)表示状态是\(s\),视野为\([i,i+5)\)的小朋友高兴的人数
- 对环的处理
环上第\(n\)个动物时的状态\(s\)的后四位必须与第\(1\)个动物的前四位的状态相同
则只需强制开始状态和结束状态一样才能更新
code
/*
@ author:pyyyyyy/guhl37
-----思路------
-----debug-------
*/
#include<bits/stdc++.h>
using namespace std;
int n,c,ans,E,F,L;
int num[50005][35],f[10005][35];
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin>>n>>c;
for(int i=1;i<=c;++i)
{
cin>>E>>F>>L;
int x,dislike=0,like=0;
for(int j=1;j<=F;++j)
{
scanf("%d",&x);
x=(x-E+n)%n;
like|=(1<<x);
}
for(int j=1;j<=L;++j)
{
scanf("%d",&x);
x=(x-E+n)%n;
dislike|=(1<<x);
}
for(int j=0;j<32;++j)
if((dislike&~j)||(like&j))
num[E][j]++;
}
for(int i=0;i<32;++i)
{
memset(f[0],128,sizeof(f[0]));
f[0][i]=0;
for(int j=1;j<=n;++j)
for(int s=0;s<32;++s)
f[j][s]=max(f[j-1][(s&15)<<1],f[j-1][(s&15)<<1|1])+num[j][s];
if(ans<f[n][i]) ans=f[n][i];
}
cout<<ans;
return 0;
}
$$Life \quad is \quad fantastic!$$