【CF1842F】Tenzing and Tree

1|0题目


题目链接:https://codeforces.com/contest/1842/problem/F
给定一棵 n 个点的树,你可以选择其中 k 个点染黑,定义一条边的价值为割去这条边之后,剩下两颗树的黑点数量差;一棵树的价值为所有边的价值之和。
对于 k[0,n],求出树的价值的最大值。
n5000

2|0思路


不妨设点 rt 为根,设 cnt[i] 表示以 i 为根的子树内的黑点数量。那么如果染 k 个黑点,答案就是

irt|(kcnt[i])cnt[i]|=irt|k2×cnt[i]|

这个绝对值很讨厌,但可以发现,如果点 rt 是所有黑点的重心的话,那么对于所有的 cnt[i] (irt),都一定满足 2×cnt[i]k,此时答案就是

(n1)×k2×irtcnt[i]

我们发现如果选择点 x 染黑,那么从 x 的父亲到 rt 上所有点的 cnt 都要加一。那么为了最大化答案,我们只需要选择深度最小的 k 个节点染黑即可。
只需要枚举每一个点作为 rt,然后 BFS 计算所有 k 的答案即可。即使目前枚举的点不是重心也没关系,因为这样就会导致有些 k2×cnt<0,不会比最优答案大。
时间复杂度 O(n2)

3|0代码


#include <bits/stdc++.h> using namespace std; const int N=5010; int n,dep[N],ans[N]; vector<int> e[N]; queue<int> q; int main() { scanf("%d",&n); for (int i=1,x,y;i<n;i++) { scanf("%d%d",&x,&y); e[x].push_back(y); e[y].push_back(x); } printf("0 %d",n-1); memset(ans,0x3f3f3f3f,sizeof(ans)); for (int i=1;i<=n;i++) { memset(dep,-1,sizeof(dep)); q.push(i); dep[i]=0; int res=0,cnt=1; while (q.size()) { int u=q.front(); q.pop(); for (auto v:e[u]) if (dep[v]==-1) { dep[v]=dep[u]+1; res+=dep[v]; cnt++; ans[cnt]=min(ans[cnt],res); q.push(v); } } } for (int i=2;i<=n;i++) printf(" %d",(n-1)*i-2*ans[i]); return 0; }

__EOF__

本文作者stoorz
本文链接https://www.cnblogs.com/stoorz/p/17509867.html
关于博主:菜死了 /fad
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   stoorz  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2020-06-27 【洛谷P6619】冰火战士
2020-06-27 【洛谷P6623】树
点击右上角即可分享
微信分享提示