Find the Maximum - 题解【思维,贪心】
题面
这是2022年ICPC昆明站的F题。在赛场上,我一开始敲了个贪心,但是出锅了,改敲树形DP,但是时间来不及了。在队友的提醒下补过了这个题,知道解法的我发现我就是个纯纯的老坛……
原题链接在牛客网:F-Find the Maximum_第46届ICPC亚洲区域赛(昆明)(正式赛),需要先登录之后才能访问。下面搬运一下原题面:
A tree with nn vertices is a connected undirected graph with \(n\) vertices and \(n-1\) edges.
You are given a tree with \(n\) vertices. Each vertex has a value \(b_i\). Note that for any two vertices there is exactly one single path between them, whereas a simple path doesn't contain any edge more than once. The length of a simple path is considered as the number of edges in it.
You need to pick up a simple path whose length is not smaller than \(1\) and select a real number \(x\). Let \(V\) be the set of vertices in the simple path. You need to calculate the maximum of \(\frac{\sum_{u\in V}(-x^2+b_{u}x)}{|V|}\).
输入描述
The first line contains a single integer \(n (2\le n \le 10^5)\) , indicating the number of vertices in the tree.
The second line contains \(n\) integers \(b_1,b_2,\cdots,b_n\)$(10^{-5} \leq b_i \leq $$ 10^{5})$ indicating the values of each vertex.
Each line in the next \(n−1\) lines contains two integers \(u,v\) indicating an edge in the tree.
输出描述
The output contains a single real number, indicating the answer.
Your answer will be accepted if and only if the absolute error between your answer and the correct answer is not greater than \(10^{-4}\).
时空限制
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K输入
2
3 2
1 2
输出
1.562500
大意
给出一颗无向树,树上的每一个节点都有一个权值\(b_i\),要求找到一条长度不小于1的简单路径,记路径上的节点的权值的算术平均值为\(t\),求\(\frac{t^2}{4}\)的最大值。
题解
本题权重可正可负,而最后需要求的式子是平均值的平方,因此在求解的时候需要同时考虑最大和最小两种情况。而要想路径上的节点算术平均值最大,路径的长度只能为1或者2。
为什么呢?假如有一条长度为3的路径\(L:v_1-v_2-v_3-v_4\),那么我们将其拆分成两条路径\(L_1:v_1-v_2,L_2:v_3-v_4\),由算术平均的性质,\(L\)包含的节点的算术平均不大于\(L_1,L_2\)包含节点的算术平均的最大值,也不小于其中的最小值。
我们来简单说明一下:假设\(w_i\)代表编号为\(i\)的节点的权值,那么:
$ t=\frac{w_1+w_2+w_3+w_4}{4}=\frac{w_1+w_2+w_3+w_4}{2}\times \frac{1}{2}=(\frac{w_1+w_2}{2}+\frac{w_3+w_4}{2})\times \frac{1}{2}=\frac{t_1+t_2}{2}$
也就是说\(t\)最大当且仅当\(t_1=t_2=t\),这样我们考虑长度为1的路径即可。同样的,可以将其推广到长度为\(4,5,\dots\)的路径上,它们都可以拆分成两条长度不小于1的路径,权值算术平均在拆分部分算术平均的最大值与最小值之间。因此,要找最大值,只需考虑所有长度为1或者2(即包含2个或者3个节点)的路径即可。由于权值可能为负,因此我们求出最大的正平均权值和最小的负平均权值,然后进行比较即可。
长度为1的路径边读入边处理即可,长度为2的路径可以通过一轮DFS来寻找:若指定一个节点为DFS的起点,则可以按照各节点到起点的距离将其视作一颗有向树,那么长度为2的路径就有两种情况:
(1)当前节点、当前节点的父节点以及当前节点的子节点,路径为父节点-当前节点-子节点
(2)当前节点和它的两个子节点,路径为子节点-当前节点-另一个子节点。
第一种情况可以很方便的枚举,而第二种情况,由于求的是最值,所以我们可以对所有的子节点排序,贪心地选择权值最大的前两个子节点和权值最小的前两个子节点进行讨论就可以了。
对于子节点的排序时间复杂度为\(O(nlogn)\),DFS遍历全图的复杂度为\(O(n)\),综合下来时间复杂度为\(O(nlogn)\),在题目给出的数据范围内可以接受。
代码实现如下:
#include <bits/stdc++.h>
#define GRP int T;cin>>T;rep(C,1,T)
#define FAST ios::sync_with_stdio(false);cin.tie(0);
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rrep(i,a,b) for(int i=a;i>=b;--i)
#define elif else if
#define mem(arr,val) memset(arr,val,sizeof(arr))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n;
double w[100010]; //权值
double ans;
vector< vector<int> > e; //vector实现邻接表
int u, v;
void dfs(int r, int pre) {
//将所有的子节点按照权值排序
sort(e[r].begin(), e[r].end(), [](int a, int b)->bool{
return w[a] > w[b];
});
//如果子节点有至少两个,就考虑子节点-当前节点-子节点这样的路径
if (e[r].size() > 2) {
int cnt = 0, flag = 0;
double cur = w[r];
//挑权值最大的两个节点
while (cnt != 2) {
//如果其中一个是父节点(以无向树存储,DFS只是视作有向树,因此需要排除)
if (e[r][flag] == pre) {
++flag;
continue;
}
cur += w[e[r][flag]];
++flag;
++cnt;
}
cur /= 3;
ans = max(ans, cur * cur / 4); //更新答案
cnt = 0, flag = e[r].size() - 1;
cur = w[r];
//挑权值最小的两个节点
while (cnt != 2) {
if (e[r][flag] == pre) {
--flag;
continue;
}
cur += w[e[r][flag]];
--flag;
++cnt;
}
cur /= 3;
ans = max(ans, cur * cur / 4);
}
for (int i : e[r]) {
if (i == pre) {
continue; //不能回头
}
//不是起始节点的情况下,考虑父节点-当前节点-子节点的路径
if (pre > 0) {
double t = (w[pre] + w[r] + w[i]) / 3;
ans = max(ans, t * t / 4); //更新答案
}
dfs(i, r); //继续搜索
}
}
int main() {
FAST
cin >> n;
e.resize(n + 1);
ans = 0;
rep(i, 1, n) {
cin >> w[i];
}
rep(i, 1, n - 1) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
double t = (w[u] + w[v]) / 2;
ans = max(ans, t * t / 4);
}
dfs(1, -1); //指定起始节点为第一个节点,并且指定其父节点不存在
cout << fixed << setprecision(6) << ans << endl;
return 0;
}
/*
_ _ _ _
/\ | | | | | | (_)
/ \ | | _____ _| |__| | ___ _ __ _ _ __ __ _
/ /\ \ | |/ _ \ \/ / __ |/ _ \| '__| | '_ \ / _` |
/ ____ \| | __/> <| | | | (_) | | | | | | | (_| |
/_/ \_\_|\___/_/\_\_| |_|\___/|_| |_|_| |_|\__, |
__/ |
|___/
*/
Find the Maximum - 题解【思维,贪心】的更多相关文章
- 【CF1256】Codeforces Round #598 (Div. 3) 【思维+贪心+DP】
https://codeforces.com/contest/1256 A:Payment Without Change[思维] 题意:给你a个价值n的物品和b个价值1的物品,问是否存在取物方案使得价 ...
- 2018-2019 ACM-ICPC, Asia Xuzhou Regional Contest- H. Rikka with A Long Colour Palette -思维+贪心
2018-2019 ACM-ICPC, Asia Xuzhou Regional Contest- H. Rikka with A Long Colour Palette -思维+贪心 [Proble ...
- [JZOJ5280]膜法师题解--思维+前缀和
[JZOJ5280]膜法师题解--思维+前缀和 题目链接 暴 力 过 于
- E. The Contest ( 简单DP || 思维 + 贪心)
传送门 题意: 有 n 个数 (1 ~ n) 分给了三个人 a, b, c: 其中 a 有 k1 个, b 有 k2 个, c 有 k3 个. 现在问最少需要多少操作,使得 a 中所有数 是 1 ~ ...
- [CQOI2012]模拟工厂 题解(搜索+贪心)
[CQOI2012]模拟工厂 题解(搜索+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1327574 链接题目地址:洛谷P3161 BZOJ P26 ...
- Sorted Adjacent Differences(CodeForces - 1339B)【思维+贪心】
B - Sorted Adjacent Differences(CodeForces - 1339B) 题目链接 算法 思维+贪心 时间复杂度O(nlogn) 1.这道题的题意主要就是让你对一个数组进 ...
- Codeforces Round #768 (Div. 2) D. Range and Partition // 思维 + 贪心 + 二分查找
The link to problem:Problem - D - Codeforces D. Range and Partition time limit per test: 2 second ...
- codeforces Round #440 C Maximum splitting【数学/素数与合数/思维/贪心】
C. Maximum splitting time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces Round #665 (Div. 2) D. Maximum Distributed Tree 题解(贪心+易错)
题目链接 题目大意 给你一课树,要你给每一条边分权值,每条边的权值大于0,他们的乘积等于k,而且要使得n-1条边1的数量尽可能少,定义 f(u,v)为u到v的边权和求 \(\max \sum_{i=1 ...
随机推荐
- WebGL 的 Hello World
本文整理自 div 侠于 凹凸 2022 年技术分享,简单介绍了 WebGL 画一个基础图形的流程,希望你了解之后,在使用 3d 渲染库的时候可以少点迷糊. 四种常用的页面绘图工具 关于h5页面的图形 ...
- 西门子S7-1200PLC不让下载一直报“模块具有激活的测试和调试功能,防止下载到设备”解决方法
错误如图 这是因为PLC被强制了,导致下载会报这类错误.取消强制就可以下载. 或者将cpu重置为出厂设置,也能再次下载. 参考:https://www.ad.siemens.com.cn/servic ...
- luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理)
luoguP6624 [省选联考 2020 A 卷] 作业题(莫比乌斯反演,矩阵树定理) Luogu 题外话: Day2一题没切. 我是傻逼. 题解时间 某种意义上说刻在DNA里的柿子,大概是很多人学 ...
- 一文了解MySQL的Buffer Pool
摘要:Innodb 存储引擎设计了一个缓冲池(Buffer Pool),来提高数据库的读写性能. 本文分享自华为云社区<MySQL 的 Buffer Pool,终于被我搞懂了>,作者:小林 ...
- linux下的shell脚本
先说明以下内容来自: http://c.biancheng.net/cpp/shell/ ,C语言中文网,请大家支持原作,点击链接查看. 我写下来只是作为笔记,如果侵权,请留言,立马删除. Shell ...
- SpringBean的生命周期 以及一些问题总结
SpringBean的生命周期 一.传统 Bean 的生命周期 new实例化: 可使用了 无引用时,GC回收. 二.Servlet 的生命周期 实例化Servlet对象: init初始化对象: 相应客 ...
- @Required 注解?
这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationExce ...
- MybatisPlus 多租户的常见问题
mybatis plus :https://mp.baomidou.com/guide/interceptor-tenant-line.html 如果最终执行的sql出现select查询没有租户ID, ...
- Nacos如果加载不到配置文件的Debug
进入 com.alibaba.cloud.nacos.client.NacosPropertySourceLocator#loadApplicationConfiguration 这个方法 com ...
- 面试问题之C++语言:面向对象的五个原则
五大原则: 1.单一职责原则SRP(Single Responsibility Principle):是指一个类的功能要单一,不能包罗万象.如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌 ...