https://loj.ac/problem/10174

题目描述

  动物园的动物排成环形,每个小朋友有喜欢和厌恶的动物,每个小朋友可以看到从他所在位置延伸出去\(2\)格的动物,可以选择移走动物,当移走至少一个他厌恶的动物或至少保留一个喜欢的动物时这个小朋友会高兴,求最多使多少小朋友高兴。

思路

  我们考虑对于每个位置暴力枚举每个状态,由于这个状态的只会在上一个状态中添加一个新的数字,只能为\(1\)\(0\),所以我们得出转移方程\(f[i][j]=max(f[i-1][(j\&15)<<1],f[i-1][j\&15<<1|1])+g[i][j]\),而\(g[i][j]\)表示第\(i\)个位置状态为\(j\)时的能高兴的人数,这个可以直接预处理出来。由于这是一个环所以我们需要加一维暴力枚举第一个位置的状态,而最后的状态也要符合第一维所设定的状态。

代码

#include<bits/stdc++.h>
using namespace std;

int read()
{
    int res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res*w;
}
void write(int x)
{
    if(x>9)write(x/10);
    putchar(x%10+'0');
}

int n,c;
int g[10100][40];
void init()
{
    n=read();c=read();
    for(int i=1;i<=c;i++)
    {
        int pos=read();
        int x=read(),y=read(),z,s1=0,s2=0;
        for(int j=1;j<=x;j++)
            z=read(),s1|=(1<<((z-pos+n)%n));
        for(int j=1;j<=y;j++)
            z=read(),s2|=(1<<((z-pos+n)%n));
        for(int j=0;j<32;j++)
            if((j&s1)||(~j&s2))g[pos][j]++;
    }
}
int f[10010][40];
void dp()
{
    int ans=0;
    for(int i=0;i<32;i++)
    {
        memset(f[0],-127,sizeof(f[0]));
        f[0][i]=0;
        for(int j=1;j<=n;j++)
            for(int k=0;k<32;k++)
                f[j][k]=max(f[j-1][(k&15)<<1],f[j-1][(k&15)<<1|1])+g[j][k];
        ans=max(ans,f[n][i]);
    }
    write(ans);
}
int main()
{
    init();
    dp();
}
01-04 15:15