1. 程式人生 > >【[APIO2007]動物園】

【[APIO2007]動物園】

我好\(sb\)啊,把\(>>\)打成\(<<\)結果就寫了兩節課

那個一個人只能看到五個動物顯然很鬼畜

那我們就可以壓這一維了

\(dp[i][s]\)表示從第\(i\)個位置往後數五個位置的狀態是\(s\)時最多能有幾個小朋友開心(\(0\)表示移走,\(1\)表示保留)

之後我們處理處每一個人的喜歡和害怕的狀態,往下轉移就好了

還有這是一個環,感覺非常不好處理的樣子

我們可以列舉第一個位置之後的狀態是什麼,最後的位置必須和第一個位置吻合就好了

複雜度\(O(4^5n)\)

程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define max(a,b) ((a)>(b)?(a):(b))
#define maxn 50005
int dp[10005][33];
int S[maxn],F[maxn],L[maxn];
int ans=0;
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
int n,m,now;
int main()
{
    n=read(),m=read();
    int t1,t2;
    for(re int i=1;i<=m;i++)
    {
        S[i]=read();
        t1=read(),t2=read();
        int x;
        F[i]=31;
        for(re int j=1;j<=t1;j++)
        {
            x=read()-S[i];
            if(x<0) x+=n;
            F[i]^=(1<<x);
        }
        for(re int j=1;j<=t2;j++)
        {
            x=read()-S[i];
            if(x<0) x+=n;
            L[i]|=(1<<x);
        }
    }
    for(re int s=0;s<=31;s++)
    {
        memset(dp,-20,sizeof(dp));
        now=1;
        for(re int i=0;i<=31;i++) dp[1][i]=-21232;
        dp[1][s]=0;
        while(S[now]==1) 
        {
            if((L[now]&s)||((F[now]|s)!=31)) dp[1][s]++;
            now++;
        }
        for(re int i=1;i<n;i++)
        {
            for(re int j=0;j<=31;j++)
            {
                dp[i+1][(j>>1)|(1<<4)]=max(dp[i][j],dp[i+1][(j>>1)|(1<<4)]);
                dp[i+1][j>>1]=max(dp[i][j],dp[i+1][j>>1]);
            }
            while(S[now]==i+1)
            {
                for(re int j=0;j<=31;j++)
                    if((L[now]&j)||((F[now]|j)!=31)) dp[i+1][j]++;
                now++;
            }
        }
        int t=s;
        t^=(1<<4);
        if(t>s) t-=(1<<4);
        for(re int i=0;i<=31;i++)
            if((i>>1)==t) ans=max(ans,dp[n][i]);
    }
    std::cout<<ans;
    return 0;
}