【状态压缩DP】[APIO2007]动物园
2040: 【APIO2007】动物园
时间限制: 1 Sec 内存限制: 128 MB
提交: 22 解决: 8
[提交][状态][我的提交]
题目描述
新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个小岛上,它包含一大圈围栏,每个围栏里有一种富有异国风情的动物。如下图所示:
你是动物园的公关主管。你要做的是,让每个参观动物园的游客都尽可能高
兴。今天有一群小朋友来到动物园参观,你希望能让他们在动物园度过一段美好
的时光。但这并不是一件容易的事——有些小朋友喜欢某些动物,而有些小朋友
则害怕某些动物。例如,Alex 喜欢可爱的猴子和考拉,而害怕拥有锋利牙齿的
狮子。而 Polly 会因狮子有美丽的鬃毛而喜欢它,但害怕有臭味的考拉。
你可以选择将一些动物从围栏中移走以使得小朋友不会害怕。但你移走的动
物也不能太多,否则留给小朋友们观赏的动物就所剩无几了。
每个小朋友站在大围栏圈的外面,可以看到连续的 5 个围栏。你得到了所有
小朋友喜欢和害怕的动物信息。当出现下面两种情形之一时,小朋友就会高兴:
(1)至少有一个他害怕的动物(从视线可见的范围内)被移走,或
(2)至少有一个他喜欢的动物没有被(从视线可见的范围内)移走。
例如,考虑下图中的小朋友和动物:
假如你将围栏 4 和 12 的动物移走。Alex 和 Ka-Shu 将很高兴,因为至少有
一个他们害怕的动物被移走了。这也会使 Chaitanya 高兴,因为他喜欢的围栏 6
和 8 中的动物都保留了。但是,Polly 和 Hwan 将不高兴,因为他们看不到任何
他们喜欢的动物,而他们害怕的动物都还在。这种安排方式使得三个小朋友高兴。
现在换一种方法,如果你将围栏 4 和 6 中的动物移走,Alex 和 Polly 将很高
兴,因为他们害怕的动物被移走了。Chaitanya 也会高兴,因为虽然他喜欢的动
物 6 被移走了,他仍可以看到围栏 8 里面他喜欢的动物。同样的 Hwan 也会因可
以看到自己喜欢的围栏 12 里的动物而高兴。唯一不高兴的只有 Ka-Shu。
如果你只移走围栏 13 中的动物,Ka-Shu 将高兴,因为有一个他害怕的动物
被移走。Alex, Polly, Chaitanya 和 Hwan 也会高兴,因为他们都可以看到至少一
个他们喜欢的动物。所以有 5 个小朋友会高兴。这种方法使得最多的小朋友高兴。
输入
输入的第一行包含两个整数 N, C,用空格分隔。N 是围栏数(10≤N≤10 000),
C 是小朋友的个数(1≤C≤50 000)。围栏按照顺时针的方向编号为 1,2,3,…,N。
接下来的 C 行,每行描述一个小朋友的信息,以下面的形式给出:
输出
仅输出一个数,表示最多可以让多少个小朋友高兴。
样例输入
Copy (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)
14 5
2 1 2 4 2 6
3 1 1 6 4
6 1 2 9 6 8
8 1 1 9 12
12 3 0 12 13 2
样例输出
5
提示
来源
[提交][状态][讨论版]
分析:
f[i][j]:i表示起始点,j表示动物的取舍状态。
num[i][j]表示以i开始j这种状态最多能令多少个站在j这个位置的小朋友满意。
f[i][j]=max(f[i][(j<<1)&31],f[i][(j<<1)&31+1]+num[i][j];
因为是环形,所以前4个应该固定,枚举前4个的取舍状态。
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXC 10000
#define MAXE 5
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
int n,c,x,y,e,f[MAXC+10][1<<MAXE],num[MAXC+10][1<<MAXE],ans;
void dfs(int pos,int dep,int status)
{
if (dep>4)
{
if((y&status)||(x&status)!=x)
num[e][status]++;
return;
}
dfs(pos,dep+1,status);
dfs(pos,dep+1,status|(1<<dep));
}
void dp(int st){
int q,i,j,w1,w2,r;
for(j=0;j<32;j++)
f[0][j]=0;
for(i=1;i<=n;i++)
if(i<5)
for(j=0;j<32;j++){
q=st>>(i-1);
r=(1<<(5-i))-1;
if((j&r)==q){
w1=(j<<1)&31,w2=w1+1;
f[i][j]=max(f[i-1][w1],f[i-1][w2])+num[i][j];
}
else
f[i][j]=0;
}
else if(i+4<=n)
for(j=0;j<32;j++){
w1=(j<<1)&31,w2=w1+1;
f[i][j]=max(f[i-1][w1],f[i-1][w2])+num[i][j];
}
else{
q=st&((1<<(i+4-n))-1);
for(j=0;j<32;j++)
if(j>>(n+1-i)==q){
w1=j<<1&31,w2=w1+1;
f[i][j]=max(f[i-1][w1],f[i-1][w2])+num[i][j];
}
else
f[i][j]=0;
}
for(j=0;j<32;j++)
ans=max(f[n][j],ans);
}
int main()
{
int i,j,t,cx,cy;
Read(n),Read(c);
for(i=1;i<=c;i++){
x=y=0;
Read(e),Read(cx),Read(cy);
for(j=1;j<=cx;j++)
Read(t),x|=1<<((t+n-e)%n);
for(j=1;j<=cy;j++)
Read(t),y|=1<<((t+n-e)%n);
dfs(i,0,0);
}
for(i=0;i<16;i++)
dp(i);
printf("%d",ans);
}