Luogu P3262 [JLOI2015]戰爭排程
阿新 • • 發佈:2020-08-08
題意
給定一棵高度為 \(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\)
然後這個東西就做個樹形揹包就好了。
實現的時候可以考慮爆搜一下,就可以壓縮掉 \(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); }