BZOJ1151(非权限) Luogu3622
思路
考虑f[i][s]表示i位置状态为s时的最多小朋友开心数(s用状压表示,0被移走,1没被移走)。
题目描述
新建的圆形动物园是亚太地区的骄傲。圆形动物园坐落于太平洋的一个小岛上,包含一大圈围栏,每个围栏里有一种动物。如下图所示:
解法
这里对于每个小朋友只能看到相邻的五个动物,对于每个位置我们可以改变移不移走开不开心的状态量很小,我们考虑状压DP。
先直接搞出一个数组g[i][s],表示在i这个位置设置看到的5个动物是否移走的状态下(s用状压表示,0被移走,1没被移走)可以使得该位置多少个小朋友开心,
考虑f[i][s]表示i位置状态为s时的最多小朋友开心数,我们首先枚举对于1的前四个(对于n的后四个),然后之后根据f[i-1]一直搞dp,决策往上第5个(不会对目前状态影响)移不移 方程f[i][s] = max( f[i-1][(s&15)<<1] , f[i-1][(s&15)<<1|1] +g[i][s],这里的s&15是找的对于现在状态的后四个对于上一个状态的前四个。
我们设定初始设定得那四个为S,最后ans在f[n][S<<1|1]和f[n][S<<1]里面找。
就这样搞定啦!
code:
#include<bits/stdc++.h>
using namespace std;
int n,c;
const int S = 31;
const int maxn = 10005;
int hh[maxn][S+3];
int f[maxn][S+3];
int main()
{
scanf("%d%d",&n,&c);
for(int i=1;i<=c;i++)
{
int e,f,l;
scanf("%d%d%d",&e,&f,&l);
int hp=0,xh=0;
for(int j=1;j<=f;j++)
{
int x;
scanf("%d",&x);
x=(x-e+n)%n;
hp|=(1<<x);
}
for(int j=1;j<=l;j++)
{
int x;
scanf("%d",&x);
x=(x-e+n)%n;
xh|=(1<<x);
}
for(int j=0;j<=S;j++)
{
if( (xh&j)||( (S^j)&hp ) )
{
hh[e][j]++;
}
}
}
int ans=0;
for(int s=0;s<16;s++)
{
for(int i=0;i<=S;i++) f[0][i]=-0x3f3f3f3f;
f[0][s<<1]=f[0][s<<1|1]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=S;j++)
{
f[i][j] = max( f[i-1][(j&15)<<1],f[i-1][(j&15)<<1|1] ) + hh[i][j];
}
}
ans = max( ans,max(f[n][s<<1],f[n][s<<1|1]) );
}
printf("%d",ans);
}