1. 程式人生 > 實用技巧 >Luogu P3262 [JLOI2015]戰爭排程

Luogu P3262 [JLOI2015]戰爭排程

題意

給定一棵高度為 \(n\) 的完全二叉樹,可以將節點設定成兩種狀態。如果某個葉子 \(x\) 的狀態為 \(i\) 同時他的某個祖先也為 \(i\),那麼這個葉子就會對祖先產生 \(f_{x,i}\) 的貢獻。求葉子狀態為 \(0\) 的數量小於等於 \(m\) 的最大貢獻。

\(\texttt{Data Range:}1\leq n\leq 10,m\leq 2^{n-1}\)

題解

考慮先設一個 \(f_{i,j}\) 表示到了 \(i\) 點,葉子選了 \(j\)\(0\) 的,這個子樹對祖先的總貢獻,但是會發現這個東西好像做不了。

於是考慮狀壓。設 \(f_{i,j,S}\) 表示到了 \(i\)

點,葉子選了 \(j\)\(0\),這個點的祖先的選擇的狀態為 \(S\) 時這個字數對祖先的總貢獻。

然後這個東西就做個樹形揹包就好了。

實現的時候可以考慮爆搜一下,就可以壓縮掉 \(S\) 這一維。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2051;
ll n,m,sz,res;
ll u[MAXN][15],v[MAXN][15],f[MAXN][MAXN<<1];
inline ll read()
{
    register ll num=0,neg=1;
    register char ch=getchar();
    while(!isdigit(ch)&&ch!='-')
    {
        ch=getchar();
    }
    if(ch=='-')
    {
        neg=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch-'0');
        ch=getchar();
    }
    return num*neg;
}
#define ls node<<1
#define rs node<<1|1
inline void dfs(ll node,ll sz,ll st)
{
    for(register int i=0;i<=sz;i++)
    {
        f[node][i]=0;
    }
    if(sz==1)
    {
        for(register int i=0;i<n-1;i++)
        {
            if(st&(1<<i))
            {
                f[node][1]+=u[node][i+1];
            }
            else
            {
                f[node][0]+=v[node][i+1];
            }
        }
        return;
    }
    for(register int i=0;i<2;i++)
    {
        dfs(ls,sz>>1,st<<1|i),dfs(rs,sz>>1,st<<1|i);
        for(register int j=0;j<=min(sz,m);j++)
        {
            for(register int k=0;k<=min(sz,m);k++)
            {
                f[node][j+k]=max(f[node][j+k],f[ls][j]+f[rs][k]);
            }
        }
    }
}
int main()
{
    n=read(),m=read(),sz=1<<n;
    for(register int i=sz>>1;i<sz;i++)
    {
        for(register int j=1;j<=n-1;j++)
        {
            u[i][j]=read();
        }
    }
    for(register int i=sz>>1;i<sz;i++)
    {
        for(register int j=1;j<=n-1;j++)
        {
            v[i][j]=read();
        }
    }
    dfs(1,sz-1,0);
    for(register int i=0;i<=m;i++)
    {
        res=max(res,f[1][i]);
    }
    printf("%d\n",res);
}