题目链接
题意还是自己看题吧,比较麻烦,一两句话说不清楚。
题解:
这个题是道好题。
乍一看这数据范围根本不像状压,仔细想想才会发现其实每个人只能看到5个位置,所以我们可以对5状压。
可能会有人看到的区域相同,所以我们设
表示在第
个位置,从该位置开始,连续五个位置的状态是
,有多少个视野初始位置在
的人会开心。其中对于某个二进制位,0表示该位置没有动物了,1表示该位置还有动物。
的描述有点绕,可能是我语文不太好。。。
的计算方法是把每个人喜欢和害怕的动物也状压一下,然后枚举
(32)种状态,通过位运算判断当前枚举到的状态是否能使这个人高兴。
然后我们要做的是这个环的dp,但是我们的状态却是从该位置开始连续5位的状态,所以会出现第1个位置的前5位与看成链之后的从最后一位开始的5位状态不同,那么我们要枚举这5位的所有状态,然后再从1到n进行dp。我们设
表示第
个位置,从第
个位置开始连续5个位置的状态是
最多有多少人高兴。状态转移方程应该是dp[i][j]=max(f[i][(j&15)<<1],dp[i][(j&15)<<1|1]+num[i][j],其中(j&15)是取出来当前状态的后4位,而当前状态的后4位正是第
位时状态的前4位,所以枚举
位时状态的最后一位是0还是1答案更大,取max之后再加上当前位置的贡献。
代码中最终更新ans时只用
,因为我们是枚举第一位的前5位的状态是
的情况,所以只有
是合法的,另外初始化时除了
之外的情况都赋为无穷小,只有
赋为0,让其他初始状态不会对当前枚举的初始状态的答案产生影响。
PS:上面的dp方程没用markdown,因为不会用markdown打&符号。。。(有人愿意教我markdown怎么打&符号吗)
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m,dp[50010][35],cnt[50010][35],ans;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int l=0,f=0;
for(int j=1;j<=y;++j)
{
int q;
scanf("%d",&q);
q=(q-x+n)%n;
f|=(1<<q);
}
for(int j=1;j<=z;++j)
{
int q;
scanf("%d",&q);
q=(q-x+n)%n;
l|=(1<<q);
}
for(int i=0;i<32;++i)
{
if((i&l)||((~i)&f))
++cnt[x][i];
}
}
for(int i=0;i<32;++i)
{
for(int j=0;j<32;++j)
dp[0][j]=-2e9;
dp[0][i]=0;
for(int j=1;j<=n;++j)
{
for(int k=0;k<32;++k)
{
dp[j][k]=max(dp[j-1][(k&15)<<1],dp[j-1][(k&15)<<1|1])+cnt[j][k];
}
}
ans=max(ans,dp[n][i]);
}
printf("%d\n",ans);
return 0;
}