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);
}
posted @ 2020-08-08 17:35  Karry5307  阅读(90)  评论(0编辑  收藏  举报