ecnuoj 5039 摇钱树
5039. 摇钱树
题目链接:5039. 摇钱树
感觉在赛中的时候,完全没有考虑分数规划这种做法。同时也没有想到怎么拆这两个交和并的式子。有点难受……
当出现分数使其尽量大或者小,并且如果修改其中直接相关的某个值会导致分子分母同时变化的时候,还是要多想想分数规划的做法。
下面引用一下题解
另外这两个交和并的式子,令 \(a = S \and T, b = T - a\),所以原来的式子变成了
\[\frac{|S \and T|}{|S \or T|} = \frac{a}{b + |S|}
\]所以,用分数规划的做法,二分一个答案 \(ans\),则有
\[\frac{a}{b + |S|} \ge ans \implies a - b \cdot ans \ge |S|\cdot ans
\]接下来用树上 dp 求一个最大的 \(a - b \cdot ans\) 即可。
令 \(f_{i,j}\) 表示此时 \(i\) 号点上选了 \(j\) 个子树加和起来最大的 \(a-b\cdot ans\) 值,\(x_{i,j}\) 表示这个式子中的 \(a\),\(y_{i,j}\) 表示这个式子中的 \(b\)。
那么接下来就是一个普通的树上背包的转移了,不过区别在于转移完整个 \(f_u\) 后,需要再用取整个以 \(u\) 为根构成的一颗子树去更新一下 \(f_{u,1}\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
#define IL inline
#define fi first
#define se second
#define mk make_pair
#define pb push_back
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(), (x).end()
#define dbg1(x) cout << #x << " = " << x << ", "
#define dbg2(x) cout << #x << " = " << x << endl
template<typename Tp> IL void read(Tp &x) {
x=0; int f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch == '-') f=-1; ch=getchar();}
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
x *= f;
}
int buf[42];
template<typename Tp> IL void write(Tp x) {
int p = 0;
if(x < 0) { putchar('-'); x=-x;}
if(x == 0) { putchar('0'); return;}
while(x) {
buf[++p] = x % 10;
x /= 10;
}
for(int i=p;i;i--) putchar('0' + buf[i]);
}
const int N = 100000 + 5;
const int M = 50 + 5;
int n, m;
int a[N], suma[N], sz[N], x[N][M], y[N][M];
db f[N][M];
vector<int> G[N];
struct fs {
int fz, fm;
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b);}
fs(int fz=0, int fm=1) {
if(fz == 0) this -> fm = 1;
else {
int g = gcd(fz, fm);
this -> fz = fz / g;
this -> fm = fm / g;
}
}
};
int dfs2(int u, int fa, const db& ef_x) {
int u_leaf = 0;
if(u != 1 && G[u].size() == 1) {
if(a[u] == 1) {
f[u][1] = 1.0;
x[u][1] = 1; y[u][1] = 0;
}
return ++u_leaf;
}
for(int i=0;i<=m;i++) f[u][i] = x[u][i] = y[u][i] = 0;
for(int v : G[u]) {
if(v == fa) continue;
int v_leaf = dfs2(v, u, ef_x);
for(int i=min(u_leaf,m);i>=0;i--) {
for(int j=1;j<=v_leaf && i+j <= m; j++) {
if(f[u][i] + f[v][j] > f[u][i+j]) {
f[u][i+j] = f[u][i] + f[v][j];
x[u][i+j] = x[u][i] + x[v][j];
y[u][i+j] = y[u][i] + y[v][j];
}
}
}
u_leaf += v_leaf;
}
if(suma[u] - (sz[u] - suma[u]) * ef_x >= f[u][1]) {
f[u][1] = suma[u] - (sz[u] - suma[u]) * ef_x;
x[u][1] = suma[u];
y[u][1] = sz[u] - suma[u];
}
return u_leaf;
}
array<int, 3> check(const db& x) {
dfs2(1, 0, x);
int ansu = 1, ansi = 1;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
if(f[i][j] > f[ansu][ansi]) {
ansu = i; ansi = j;
}
}
return {f[ansu][ansi] >= suma[1] * x, ansu, ansi};
}
void dfs1(int u, int fa) {
suma[u] += a[u];
sz[u] = 1;
for(int v : G[u]) {
if(v == fa) continue;
dfs1(v, u);
suma[u] += suma[v];
sz[u] += sz[v];
}
}
void solve() {
read(n); read(m);
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<n;i++) {
int u, v; read(u); read(v);
G[u].pb(v); G[v].pb(u);
}
dfs1(1, 0);
db L = 0.0, R = 1.0;
fs ans;
while(R - L >= 1e-10) {
db M = (L + R) / 2.0;
auto arr = check(M);
if(arr[0]) {L = M; ans = fs(x[arr[1]][arr[2]], y[arr[1]][arr[2]] + suma[1]);}
else R = M;
}
write(ans.fz); putchar(32); write(ans.fm); putchar(10);
}
int main() {
#ifdef LOCAL
freopen("test.in", "r", stdin);
// freopen("test.out", "w", stdout);
#endif
int T = 1;
// read(T);
while(T--) solve();
return 0;
}
ecnuoj 5039 摇钱树的更多相关文章
- 摇钱树运营小工具UI设计.vsd
去年,我负责公司的一个互联网投融资平台——摇钱树.系统运营过程中,业务和客服那边不断的反馈一些事情让技术这边协助实现.例如,土豪客户忘记登录密码后懒得自己重置,更愿意选择搭讪客服MM:再比如,客户多次 ...
- BZOJ 5039: [Jsoi2014]序列维护
5039: [Jsoi2014]序列维护 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 282 Solved: 169[Submit][Status ...
- hdu 5039 线段树+dfs序
http://acm.hdu.edu.cn/showproblem.php?pid=5039 给定一棵树,边权为0/1.m个操作支持翻转一条边的权值或者询问树上有多少条路径的边权和为奇数. 用树形df ...
- 洛谷 P1987 摇钱树
题目戳 题目描述 Cpg 正在游览一个梦中之城,在这个城市中有n棵摇钱树...这下,可让Cpg看傻了...可是Cpg只能在这个城市中呆K天,但是现在摇钱树已经成熟了,每天每棵都会掉下不同的金币(不属于 ...
- P1987 摇钱树
题意:有n棵摇钱树,k天,每天可砍一棵并获得其金币 每棵树初始有$a_i$个金币,每天减少$b_i$个 问k天得到的最多金币数 这题很明显是DP(锻炼自己的机会来了QAQ) 设$f[i][j]$ ...
- Leetcode 5039. 移动石子直到连续
第134次周赛 5039. 移动石子直到连续 5039. 移动石子直到连续 三枚石子放置在数轴上,位置分别为 a,b,c. 每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < ...
- HDU 5039 Hilarity
题意:一棵树n个结点,每条边有0.1两种权值,每次询问权值为奇数的路径数目,或者改变某一条边的权值. 分析:这个题目很巧妙低利用了异或和的特性,dfs得到每个点到根结点的权值异或和,然后奇数则为1,偶 ...
- 洛谷 - P1987 - 摇钱树 - dp - 贪心
https://www.luogu.org/problemnew/show/P1987 这道题,假如是n==k,也就是把所有的树都砍完,我就知道要贪心去做,因为树给的初始金币是固定的,每天掉金币,当然 ...
- ECNUOJ 2142 放书
放书 Time Limit:1000MS Memory Limit:65536KBTotal Submit:409 Accepted:173 Description 你要把一叠书放进一些箱子里面,为 ...
- ECNUOJ 2147 字符环
字符环 Time Limit:1000MS Memory Limit:65536KBTotal Submit:562 Accepted:146 Description 字符环:就是将给定的一个字符串 ...
随机推荐
- 2019-3-15-uwp-ScrollViewer-content-out-of-panel-when-set-the-long-width
title author date CreateTime categories uwp ScrollViewer content out of panel when set the long widt ...
- k8s七层代理Ingress-nginx-controller
一.Ingress与Ingress Controller概述 1.1 回顾service四层代理 在 k8s 中为什么要做负载均衡? Pod 漂移问题,可以理解成 Pod IP 是变化的 Kubern ...
- 数据分析之重要模块pandas
1.简介 基于Numpy构建 pandas的出现,让Python语言成为使用最广泛而且强大的数据分析环境之一 pandas的主要功能 - 具备诸多功能的两大数据结构 Series.DataFrame( ...
- Premiere cc 2019之声音处理
目录 deepin录视频 调整声道 查看声音轨道 转化格式 提取二声道的台词音,或者背景音 降噪 1.无需AU!PR自带音频模块完美实现降噪.增强人声.模拟环境 2.Adobe audition中降噪 ...
- 热烈祝贺 Splashtop 赢得最佳远程桌面用户满意度得分
在 G2 的 2021 年冬季远程桌面网格报告中,Splashtop 的净发起人得分(NPS)为 93,是所有远程桌面工具中最高的. 在一份分析用户对 30 多种远程桌面解决方案的评论的报告中,Spl ...
- 机器学习策略篇:详解为什么是人的表现?(Why human-level performance?)
为什么是人的表现? 在过去的几年里,更多的机器学习团队一直在讨论如何比较机器学习系统和人类的表现,为什么呢? 认为有两个主要原因,首先是因为深度学习系统的进步,机器学习算法突然变得更好了.在许多机器学 ...
- 2023年的Clion内建立多个子项目(保姆级教程)
目录 下载插件C/C++ Single File Execution 项目操作 其他操作 下载插件C/C++ Single File Execution 项目操作 1.新建项目-->如图所示操作 ...
- Python:当函数做为参数时的技巧
我们之前在<Python技法3: 匿名函数.回调函数.高阶函数>中提到,可以通过lambda表达式来为函数设置默认参数,从而修改函数的参数个数: import math def dista ...
- kubernets之init容器作用
一 init容器的作用 1.1 init容器是在pod的生命周期,保证该pod运行的一些前置条件满足之后才开始运行这个pod,例如需要依赖一些其他的pod,服务等,可以去对这些服务的状态进行检测, ...
- 腾讯面试:如何提升Kafka吞吐量?
Kafka 是一个分布式流处理平台和消息系统,用于构建实时数据管道和流应用.它最初由 LinkedIn 开发,后来成为 Apache 软件基金会的顶级项目. Kafka 特点是高吞吐量.分布式架构.支 ...