【题解】APIO2007动物园

  首先一眼感受到这题特别的性质……5个?这么小的,感觉就像是状压。脑补了一下,如果没有环的话应该很好做吧……有环怎么办?5真的很小的,随便乱搞肯定也可以。那就放在外面暴力枚举吧。然后正解就出来了。

  然而这题题面真的有毒吧。说好的不能全部选走?我还多加了一个维度,结果数据里面允许全部取走……然后对于<5的点单独写了个爆搜。代码奇长……大家看看就好吧(以及位运算本人一贯以来又清奇又暴力的脑回路……)

  dp[][][0/1],1代表已经保留了至少一个动物……如果要A掉此题的话把转移那里加上dp[][][0]的就好了。整个namespace Speacial都是特判的点……(虽然数据里面并没有)

#include <bits/stdc++.h>
using namespace std;
#define CNST 32
#define maxn 10300
int n, c, tot, fans = 0, dp[maxn][CNST][2];
int num1[maxn * 5], num2[maxn * 5];
int lst[6] = {0, 1, 3, 7, 15, 31};
int fst[6] = {0, 16, 24, 28, 30, 31};
vector <int> V[maxn];

int read()
{
    int x = 0;
    char c;
    c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

void gmax(int &a, int b)
{
    a = a > b ? a : b;
}

void print(int x)
{
    int a[15], tot = 0;
    a[5] = a[4] = a[3] = a[2] = a[1] = 0;
    while(x)
    {
        a[++ tot] = x & 1;
        x >>= 1;
    }
    for(int i = 5; i; i --)
        printf("%d", a[i]);
    return;
}

void work(int x, int sum, int opt)
{
    int tem = 0;
    for(vector <int> :: iterator i = V[x].begin(); i < V[x].end(); i ++)
    {
        int k = *i;
        if((sum & num2[k]) || (num1[k] > (sum & num1[k]))) tem ++;
    }
    dp[x][sum][opt] += tem;
    int k1 = (sum << 1) & (fst[4]), k2 = (((sum << 1) & (fst[4])) | 1);
    gmax(dp[x + 1][k1][opt], dp[x][sum][opt]);
    gmax(dp[x + 1][k2][1], dp[x][sum][opt]);
}

int Check(int now, int sum)
{
    int ans = 0;
    for(int i = 1; i <= 4; i ++)
    {
        int a = now, b = sum, t = 0;
        t = a & (lst[5 - i]); t <<= i;
        t |= ((b & (fst[i])) >> (5 - i));
        for(vector <int> :: iterator j = V[i].begin(); j < V[i].end(); j ++)
        {
            int k = *j;
            if((t & num2[k]) || (num1[k] > (t & num1[k]))) ans ++;
        }
    }
    return ans;
}

int DP(int sum, int opt)
{
    memset(dp, -1, sizeof(dp));
    int ans = 0;
    dp[5][sum][opt] = 0;
    work(5, sum, opt);
    for(int i = 6; i <= n; i ++)
    {
        int maxx = 0;
        for(int j = 0; j < CNST; j ++)
            for(int k = 0; k <= 1; k ++)
            {
                if(~dp[i][j][k]) work(i, j, k);
                maxx = max(maxx, dp[i][j][k]);
            }
    }    
    for(int j = 0; j < CNST; j ++)
    {
        if(dp[n][j][1] == -1) continue;
        int p = Check(j, sum);
        ans = max(ans, p + dp[n][j][1]);
    }
    return ans;
}

void dfs(int x, int sum)
{
    if(x == 5)
    {
        sum <<= 1;
        if(sum & (CNST - 1)) fans = max(fans, DP(sum, 1));
        else fans = max(fans, DP(sum, 0));
        sum |= 1;
        fans = max(fans, DP(sum, 1));
        return;
    }
    sum <<= 1;
    dfs(x + 1, sum);
    dfs(x + 1, sum |= 1);
}

int main()
{
    n = read(), c = read();
    for(int i = 1; i <= c; i ++)
    {
        int E = read(), F = read(), L = read();
        int id = E + 4; if(id > n) id -= n;
        V[id].push_back(++ tot);
        for(int j = 1; j <= F; j ++) //害怕 
        {
            int x = read(); x = id - x;
            if(x < 0) x += n;
            num1[tot] |= (1 << x); 
        }
        for(int j = 1; j <= L; j ++) //喜欢 
        {
            int x = read(); x = id - x;
            if(x < 0) x += n;
            num2[tot] |= (1 << x);
        }
    }
    dfs(1, 0);
    printf("%d\n", fans);
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/twilight-sx/p/9024871.html