P3262 [JLOI2015]戰爭排程 - 樹形 dp,狀壓 dp
阿新 • • 發佈:2021-11-01
題解
由於這是一棵滿二叉樹,所以其樹高只有 \(n\)。
設 \(f_{i,j,S}\) 為 \(i\) 的子樹內,有 \(j\) 個平民參戰,且 \(\operatorname{fa}(i)\sim 1\) 的路徑上的點,顏色為 \(S\) 的對應二進位制位。轉移就是普通的樹上揹包。
乍一看時間複雜度不太對,但 \(f\) 只有 \(\sum_{i=1}^n 2^i\times 2^{n-i}\times 2^i\) 個狀態;一個狀態 \((i,j,S)\) 的轉移複雜度是 \(\mathcal{O}(j)\)。於是總複雜度是 \(\mathcal{O}(n4^n)\)。
但這樣 \(f\)
Bonus:應該可以通過上下界優化,讓時間複雜度變成 \(\mathcal{O}(4^n)\)?
程式碼
#include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <vector> using namespace std; #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti) #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti) template<typename T> void Read(T &_x){ _x=0;int _f=1; char ch=getchar(); while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar(); while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar(); _x*=_f; } template<typename T,typename... Args> void Read(T &_x,Args& ...others){ Read(_x);Read(others...); } typedef long long ll; const int Vertex=1030; int n,m,son[Vertex][2],fa[Vertex],dep[Vertex],cont[Vertex][Vertex][2]; ll f[Vertex][Vertex]; void Dfs(int u,int stat){ memset(f[u],0,sizeof(f[u])); if(!son[u][0]){ for(int v=fa[u],st=stat;v;v=fa[v],st>>=1){ if(st&1) f[u][1]+=cont[u][v][1]; else f[u][0]+=cont[u][v][0]; } return; } For(i,0,1){ Dfs(son[u][0],stat<<1|i); Dfs(son[u][1],stat<<1|i); int mx=(1<<(n-dep[u])); For(j,0,min(mx,m)){ For(k,0,j){ f[u][j]=max(f[u][j],f[son[u][0]][k]+f[son[u][1]][j-k]); } } } } int main(){ Read(n,m); For(i,1,(1<<(n-1))-1) son[i][0]=i<<1,son[i][1]=i<<1|1; For(i,1,(1<<n)-1) fa[i]=i/2,dep[i]=dep[fa[i]]+1; For(i,1,1<<(n-1)){ int u=(1<<(n-1))+i-1,v=fa[u]; For(j,1,n-1){ int x;Read(x); cont[u][v][1]=x; v=fa[v]; } } For(i,1,1<<(n-1)){ int u=(1<<(n-1))+i-1,v=fa[u]; For(j,1,n-1){ int x;Read(x); cont[u][v][0]=x; v=fa[v]; } } Dfs(1,0); ll ans=0; For(i,0,m) ans=max(ans,f[1][i]); printf("%lld\n",ans); return 0; }