D. The Omnipotent Monster Killer

news/2024/11/16 13:38:11/文章来源:https://www.cnblogs.com/autumnmist/p/18327831

D. The Omnipotent Monster Killer

题目大意:
有一棵树,树节点数不超过\(3·10^5\),每个节点的权值,定义为数组\(a(a_i<10^{12})\),初始\(sum=0\),每一轮执行如下操作:

  • 计算当前剩余所有的点权和,累计到\(sum\)
  • 任选若干个互不相邻的节点并移除

重复这个操作直到树上没有任何节点为止,最小化\(sum\)

整体感觉这道题带来的启发很多,值得慢慢细品。

首先第一个误区以为可以贪心的两轮操作结束,比如:

先移除2 4,再移除1 3。
但是很容易举出反例:

显然要先移除4 5,再移除一个2,最后移除剩余的1,需要三轮才能完成。
三轮能否确定结束呢?如果是链式结构确实是可以的,因为链式结构中,任意节点最多只有两个节点相邻,这三者互不相同也只有三轮操作。
而在树上,某个节点N相邻可能有n个\(X_i\),如果每一个均在不同轮次移除,那么节点N需要在第\(n+1\)轮才能移除。

然后是第二个误区,是否每轮选择树上最大独立集?即任选互不相邻节点,树形dp求权重和最大的选择。
这个可以解决上面1-2-3-4和5-2-1-4两种情况。
如果有多轮,似乎也可以解决,然而这也是不对的,简单反例如下:

第一轮最大独立集是(5,6),然而剩余的(3,4)由于是相邻的,只能先选4再选3,\(sum=(6+5+4+3)+(4+3)+3=28\)
而选择(4,6),则有\(sum=(6+5+4+3)+(5+3)=26\)

综上我们得出两个结论,第一需要多轮操作才可能最小化\(sum\),第二最大独立集的贪心思路是错误的。
此时一个关键问题摆在了我们面前,我们最多可能需要多少轮操作呢?
构造多轮的树结构不是那么容易,赛时也挺难悟到,这里给出一个建树方式

  • 初始只有两个节点1,此时我们需要一轮操作

  • 添加一个节点2,此时我们需要两轮操作

  • 在1和2节点上添加4和5,此时由于我们需要先移除(4,5),所以需要三轮操作

  • 下面是递推的构造,在之前出现的所有节点上,添加(8-11),此时第一轮移除(8-11)是最优的,加上之前的三轮,我们就需要四轮操作

  • ...重复下去,每轮添加的节点个数是\(2^{x-2}\),节点权值分别是\([2^{x-1},2^{x-1}+2^{x-2}-1]\)

这样需要x轮操作移除所有节点的情况下,节点总数需要\(2^{x-1}\),而节点总数是\(n\)的情况下,我们至多需要的轮数就是\(logn+1\)
这是第一个难点,需要能推算到至多需要的轮数是\(logn+1\) 不妨设\(T=logn+1\)
讨论真正的做法前,我们需要反思以下:
之前常做的树形dp往往是对一个节点的操作是选或者不选这种两个状态的转移,典型就是树的最大独立集。
就算是多节点多状态也往往是题意里推导出的带有意义的固定个数,比如968. 监控二叉树
这导致很容易把树形dp中dp的内涵忽略,对本题而言,虽然是树形dp,但是节点却是有\(T=logn+1\)这样一个状态数。
因此第二个难点就是,要能发现树形dp的状态需要定义为数组\(dp[i][j]\),其中\(i\)为节点,\(j∈[1,T]\)。每个节点可能出现在任何一轮,而如果节点在第x轮移除,那么他产生的对\(sum\)的贡献为\(x*a_i\)

然后如何进行状态转移呢?每个节点需要基于所有子节点的状态进行转移
这是难点三,推导转移方程。每个节点的初始都是一致的,即每轮的自身代价。
这里假设节点i有k个子节点,转移中,是对于每个自身轮数,需要依次累加子节点不同轮数的最小\(sum\)
\(f[i][j]= dp[i][j] + \sum_{s=1}^k(min(f[s][t]),(t∈[1,T],t≠j))\)
简单枚举每个\(j∈[1,T]\),再枚举子节点\(t∈[1,T]\),取\(j≠t\)的最小值,复杂度为\(O(log^2n)\)
整体复杂度\(O(nlog^2n)\)
不过这里有个经典小技巧用于处理这个问题。
对于每个\(t∈[1,T]\),可以遍历依次统计\(dp[s][t]\)的最小值min和次小值min2
然后对于每个\(j\),则有

\[\begin{flalign} &\ f[i][j] = \begin{cases} min, & f[s][t] ≠ min \\ min2, & f[s][t] = min \\ \end{cases} & \end{flalign} \]

所以整体复杂度可以降为\(O(nlogn)\)
核心代码如下(未使用该技巧,本题没卡log)

long[][] f = new long[n][];
for(int i = 0; i < n; i++) f[i] = new long[T];
void DFS(int u, int fa)
{for(int k = 0; k < T; k++){f[u][k] = (k + 1) * w[u];}foreach(int v in g[u]){if(v == fa) continue;DFS(v, u);for(int k = 0; k < T; k++){long min = long.MaxValue;for(int s = 0; s < T; s++){if(s != k) min = Math.Min(min, f[v][s]);}f[u][k] += min;}}
}
DFS(0, -1);
long ans = long.MaxValue;
for(int i = 0; i < T; i++) ans = Math.Min(f[0][i], ans);
Print(ans);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/772879.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php 使用swoole 创建websocket服务

下载对应版本的swoole扩展, 我的php版本是7.4, 所以下载的swoole版本为4.8.* 地址如下https://pecl.php.net/package/swoole 通过源码编译安装, 可以参考官方文档https://wiki.swoole.com/zh-cn/#/environment 修改php.ini 开启扩展 extension=swoole.so 重启web服务器 php -m …

Labview笔记

1. 背景 Labview这个软件,从大学到现在,装了卸载,卸载了又装。来来回回不下10次了,那本大学时的教材Labview 2010基础教程,一直没丢,但也一直没看过。最近又装回来了,准备简单的系统性倒腾一下,当是个了解。一些杂项:快捷键:Ctrl+N:创建一个Labview项目 Ctrl+E:切换前…

二值图像

一、 二值图像概念 1. 二值图像含义二值图像(Binary Image)是指将图像上的每一个像素只有两种可能的取值或灰度等级状态,人们经常用黑白、B&W、单色图像表示二值图像。 二值图像是指在图像中,灰度等级只有两种,也就是说,图像中的任何像素点的灰度值均为0或者255,分别…

17、flask-图书简单馆项目

为了掌握模型可以练一下、以下是代码: app.py from App import create_appapp = create_app()if __name__ == __main__:app.run(debug=True)views.py from flask import Blueprint, render_template from datetime import datetime from .models import *#创建蓝图(路由) bl…

全网最适合入门的面向对象编程教程:25 类和对象的Python实现-Python判断输入数据类型

本文主要介绍了在使用Python面向对象编程时,如何使用type函数、isinstance函数和正则表达式三种方法判断用户输入数据类型,并对相关语法进行介绍。全网最适合入门的面向对象编程教程:25 类和对象的 Python 实现-Python 判断输入数据类型摘要: 本文主要介绍了在使用 Python …

[数据结构] 堆与堆排序

本文介绍了堆这种数据结构的性质,以及堆排序算法,最后介绍了堆的相关应用场景。这篇文章使用 JavaScript 语言进行相关代码的编写。数据结构——堆 heap 基本概念与性质 堆是一颗完全二叉树,根据父子节点之间值的大小关系可以分为:大根堆:每一个节点的值 大于或等于 其子节…

详解 Hough 变换(基本原理与直线检测)

Hough 变换原理与应用前言: 详细介绍了 Hough 变换的基本思想、基本原理和应用等。其中大多都是自己的理解,难免有偏差,仅供参考。文章目录Hough 变换原理与应用1. 基本概述1.1 一些基本问题 1.2 以例子说明1.2.1 例子1:直线 y = k x + b y = kx + by=kx+b​​​​​​​ 到…

致远AnalyticsCloud分析云任意文件读取漏洞复现

产品界面图:FOFA:"AnalyticsCloud分析云"GET请求payload即可读取文件内容paylaod: /.%252e/.%252e/c:/windows/win.ini/a/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252…

分形之城 - 题解

分形之城时间限制:C/C++ 1000MS,其他语言 2000MS 内存限制:C/C++ 256MB,其他语言 512MB描述 城市的规划在城市建设中是个大问题。 不幸的是,很多城市在开始建设的时候并没有很好的规划,城市规模扩大之后规划不合理的问题就开始显现。 而这座名为 Fractal 的城市设想了这样…

开天辟地,环境安装(cangjie篇)

cangjie,尝鲜日记需求:安装好环境,输出hello world(程序员金字招牌,哈哈~)开整!1 下载SDK 由于官方关闭了开放下载入口,需要走申请、审核机制。然后gitcode平台,下载安装。我们这里就不方便提供下载地址了。目前,我安装的0.53.4b版本。如图:下载步骤就不赘述了,下一…

pycharm远程调试一直卡着(正在收集数据),查看变量时一直显示collecting data并报错Timeout waiting for response且看不到任何内容

1. 问题描述如题,在用PyCharm进行Python代码调试查看具体变量时,会随机遇到一直显示collecting data,到最后报错Timeout waiting for response,在界面中看不到变量内部的内容,如下图所示:2. 解决办法在PyCharm,打开Setting界面,在如下设置项中勾选“Gevent compatible”…

python错题记录:布尔运算与逻辑值检测

一 前言 环境:python 3.10 win10 二 布尔运算与逻辑值检测 1 案例 案例1如上,在布尔运算时,有些时候代码只会运算前面的一部分,剩下的部分根本不会运算。以前在练习算法代码时,就利用这个规则来减少代码的工作量 案例2如上,之前好长一段时间,上面的布尔运算总是让我感…