当前位置: 首页 > news >正文

「HDU6566-The Hanged Man」题解

The Hanged Man

sol

题意大致就是对于每一个 \(i\in[1,m]\) 求树上独立集 \(S\) 满足 \(\sum\limits_{i\in S}a_i\le m\)\(\sum\limits_{i\in S}b_i\) 最大的 \(S\) 个数。

首先有个很显然的暴力树型 DP,是 \(O(nm^2)\) 的。

考虑优化这个东西,暴力的复杂度问题显然在 \(m^2\),这是由于要合并子树背包,然而单次插入一个值是 \(O(m)\) 的。因此,考虑按 dfs 序顺序背包。

这样的话,各个点能否加入背包就只与其的父节点有关,我么需要知道各个点的父节点的状态,直接状压这个东西是 \(O(2^n)\) 的,显然很伪。

然而不难发现,当所有子节点都处理过之后,这个父节点实际上就没用了,我们不再需要它的状态。考虑只维护当前点到根节点一路上的节点状态,然而这样仍然会被卡成 \(2^n\)

再优化一点,如果当前点是其父节点的最后一个处理的儿子,那么其父节点在处理完当前点后已经没用了。如何尽可能地减少当前点到根路径上仍有子节点未被处理的节点数呢?

考虑重链剖分,每个点优先处理轻儿子再处理重儿子,那么从一个轻子树跳到下一个子树时,必然会跳过整条重链,那么整条重链内的点都无需额外记录,那么一个点需要记录的节点就是其到根的路径上经过的所有重链的链头的父节点,这个是 \(\log n\) 级别的。

然后就得到了 \(O(n^2m)\) 的做法。

但这真是太麻烦了,考虑乱搞,优化一下暴力,如果当前状态不存在就不背包。由于子树中存在的状态数为 \(2^{siz}\) 级别,这是一个很有用的优化。然后就过了。后面的代码给的是乱搞做法 qwq

code

const int N=55,M=5005;int n,m;
int a[N],b[N];
vec<int> G[N];ll f[N][M][2],g[N][M][2];
void dfs(int x=1,int fa=0){f[x][a[x]][1]=b[x];f[x][0][0]=0;g[x][a[x]][1]=g[x][0][0]=1;for(auto y:G[x])if(y!=fa){dfs(y,x);per(i,m,0){if(~f[x][i][0])per(j,m-i,0)if(~f[y][j][0]||~f[y][j][1]){int t=max(f[y][j][0],f[y][j][1]);if(f[x][i+j][0]<f[x][i][0]+t||!j){f[x][i+j][0]=f[x][i][0]+t;if(f[y][j][0]==f[y][j][1])g[x][i+j][0]=g[x][i][0]*(g[y][j][0]+g[y][j][1]);else if(f[y][j][0]<f[y][j][1])g[x][i+j][0]=g[x][i][0]*g[y][j][1];else g[x][i+j][0]=g[x][i][0]*g[y][j][0];}else if(f[x][i+j][0]==f[x][i][0]+t){if(f[y][j][0]==f[y][j][1])g[x][i+j][0]+=g[x][i][0]*(g[y][j][0]+g[y][j][1]);else if(f[y][j][0]<f[y][j][1])g[x][i+j][0]+=g[x][i][0]*g[y][j][1];else g[x][i+j][0]+=g[x][i][0]*g[y][j][0];}}if(~f[x][i][1])per(j,m-i,0)if(~f[y][j][0]){if(f[x][i+j][1]<f[x][i][1]+f[y][j][0]||!j){f[x][i+j][1]=f[x][i][1]+f[y][j][0];g[x][i+j][1]=g[x][i][1]*g[y][j][0];}else if(f[x][i+j][1]==f[x][i][1]+f[y][j][0]){g[x][i+j][1]+=g[x][i][1]*g[y][j][0];}}}}
}inline void Main(){cin>>n>>m;rep(i,1,n)cin>>a[i]>>b[i],G[i].clear();rep(i,1,n)rep(j,0,m)rep(k,0,1)f[i][j][k]=-1,g[i][j][k]=0;repl(i,1,n){int x,y;cin>>x>>y;G[x].pub(y),G[y].pub(x);}dfs();rep(i,1,m){if(f[1][i][0]==f[1][i][1])cout<<g[1][i][0]+g[1][i][1]<<" ";else if(f[1][i][0]<f[1][i][1])cout<<g[1][i][1]<<" ";else cout<<g[1][i][0]<<" ";}cout<<'\n';
}
int main(){// ReadFile(___);#define MultiTasksios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#ifdef MultiTasksint t;cin>>t;rep(i,1,t)cout<<"Case "<<i<<":\n",#endifMain();return 0;
}
http://www.aitangshan.cn/news/921.html

相关文章:

  • 从Tushare到Wind,散户的Python量化系统搭建实录
  • 内存溢出、内存泄露、内存逃逸三者的区别
  • CentOs8中vi以及vim编辑中文乱码问题
  • ceph日常维护
  • svn
  • Linux 中 同时提取文件的前几行和最后几行
  • CancellationTokenSource 与 CancellationTokenSourceToken
  • 弧焊机器人气体节能指南
  • MSE ZooKeeper:Flink 高可用架构的企业级选择
  • frp内网穿透详解
  • Vue 中如何重置data?
  • linux常用命令工具及问题解决方法系列2
  • 基于线段树的数据结构 - β
  • 华为_DHCP
  • Redis Stream:实时数据流的处理与存储
  • ceph部署
  • 学习记录:23ai新特性:Priority Transactions
  • iOS代码混淆工具怎么选 适合小团队的实用指南
  • 2025 08 12
  • Nginx配置:负载均衡
  • 读书笔记:白话Oracle重做与撤销:数据库的后悔药和时光机
  • Java面向对象
  • 智能台灯离线语音控制芯片方案与应用场景
  • Luogu P3287 [SCOI2014] 方伯伯的玉米田 题解 [ 紫 ] [ 多维 DP ] [ 贪心 ] [ 树状数组 ] [ 状态设计优化 ]
  • VSCode添加到右键菜单中
  • css 红包打开静态效果
  • 厂商官网
  • Java基础学习的一些小细节
  • 2025.8.12 java课堂笔记
  • 记录---高效前端开发:使用 unplugin-auto-import 实现依赖自动导入