cogs 2652. 秘术「天文密葬法」(0/1分数规划 长链剖分 二分答案 dp

http://cogs.pro:8080/cogs/problem/problem.php?pid=vSXNiVegV

题意:给个树,第i个点有两个权值ai和bi,现在求一条长度为m的路径,使得Σai/Σbi最小。

思路:二分答案得p,把每个点权值变成ai-p*bi,看是否存在长为一条长为m的路使总和<=0。

tag数组表示从当前位置沿最长链走到底的值,dp数组初值表示从当前位置的重儿子走到底的值(加负号),用tag[...]+dp[..]维护从当前节点往下走若干步得到的最小值(只更新dp数组

  1 # include <stdio.h>
  2 # include <string.h>
  3 # include <iostream>
  4 # include <algorithm>
  5 // # include <bits/stdc++.h>
  6
  7 using namespace std;
  8
  9 typedef long long ll;
 10 typedef long double ld;
 11 typedef unsigned long long ull;
 12 const int N = 3e4 + 10, M = 6e4 + 10;
 13 const int mod = 1e9+7;
 14
 15 int n, m, A[N * 7], B[N * 7], head[N], nxt[M], to[M], tot = 0;
 16 inline void add(int u, int v) {
 17     ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
 18 }
 19 inline void adde(int u, int v) {
 20     add(u, v), add(v, u);
 21 }
 22
 23 int dep[N], mxd[N], son[N], sz[N];
 24 inline void pre_dfs(int x, int fa = 0) {
 25     dep[x] = dep[fa] + 1;
 26     mxd[x] = dep[x]; son[x] = 0;
 27     for (int i=head[x]; i; i=nxt[i]) {
 28         if(to[i] == fa) continue;
 29         pre_dfs(to[i], x);
 30         if(mxd[to[i]] > mxd[x]) mxd[x] = mxd[to[i]], son[x] = to[i];
 31     }
 32     sz[x] = mxd[x] - dep[x];
 33 }
 34
 35 int pos[N], idx;
 36 inline void pre_pos(int x, int fa = 0) {
 37     pos[x] = ++idx;
 38     if(son[x]) pre_pos(son[x], x);
 39     for (int i=head[x]; i; i=nxt[i])
 40         if(to[i] != fa && to[i] != son[x]) pre_pos(to[i], x);
 41 }
 42
 43 double mid_check, ans;
 44 double dp[N], tag[N];
 45 inline void solve(int x, int fa = 0) {
 46     double *f = &dp[pos[x]], C = (double)A[x] - mid_check * B[x];
 47     if(son[x] == 0) {    //leaf
 48         f[0] = 0; tag[x] = C;
 49         if(m == 0) ans = min(ans, tag[x]);
 50         return ;
 51     }
 52     solve(son[x], x); f[0] = -tag[son[x]];
 53     tag[x] = tag[son[x]] + C;
 54     for (int i=head[x], y; i; i=nxt[i]) {
 55         if(to[i] == fa || to[i] == son[x]) continue;
 56         solve(y = to[i], x);
 57         double *g = &dp[pos[y]];
 58         for (int j=0; j<=sz[y] && j<m; ++j)
 59             if(m-1-j <= sz[x]) ans = min(ans, f[m-1-j] + tag[x] + g[j] + tag[y]);
 60          for (int j=0; j<=sz[y]; ++j) f[j+1] = min(f[j+1], g[j] + tag[y] + C - tag[x]);
 61     }
 62     if(m <= sz[x]) ans = min(ans, f[m] + tag[x]);
 63 }
 64
 65
 66 inline bool chk(double x) {
 67      ans = 1e18; mid_check = x;
 68      solve(1);
 69     return ans <= 0;
 70 }
 71
 72 int main() {
 73     freopen("cdcq_b.in", "r", stdin);
 74     freopen("cdcq_b.out", "w", stdout);
 75     cin >> n >> m;
 76     for (int i=1; i<=n; ++i) scanf("%d", A+i);
 77     for (int i=1; i<=n; ++i) scanf("%d", B+i);
 78     if(m == -1) {
 79         double ans = 1e18;
 80         for (int i=1; i<=n; ++i) ans = min(ans, (double)A[i]/B[i]);
 81         printf("%.2lf\n", ans);
 82         return 0;
 83     }
 84     for (int i=1, u, v; i<n; ++i) {
 85         scanf("%d%d", &u, &v);
 86         adde(u, v);
 87     }
 88     --m;
 89     pre_dfs(1);
 90     pre_pos(1);
 91     double l = 0, r = 1e11, mid;
 92     while(r-l > 1e-4) {
 93         mid = (l+r)/2.0;
 94         if(chk(mid)) r = mid;
 95         else l = mid;
 96     }
 97     if(l > 5e10) puts("-1");
 98     else printf("%.2lf\n", l);
 99     return 0;
100 }

原文地址:https://www.cnblogs.com/wzgg/p/11406298.html

时间: 2024-10-08 01:51:15

cogs 2652. 秘术「天文密葬法」(0/1分数规划 长链剖分 二分答案 dp的相关文章

cogs2652 秘术「天文密葬法」

传送门:http://cogs.pro/cogs/problem/problem.php?pid=2652 [题解] 学习了一发长链剖分,感觉十分兹磁 广告:长链剖分 - fjzzq2002 那么我再说一遍吧,以本题为例. 题目大意:给一棵树,每个点有点权$A_i$和$B_i$,找一条长度为$m$的路径,使得$\frac{\sum_{j~in~route}A_j}{\sum_{j~in~route}B_j}$最小. 显然分数规划,二分答案$p$,那么将每个点的点权变成$A_j - p*B_j$,

「一根手指」背後的大數據生意

大家好!我是識益科技的聯合創始人劉志彬. 首先,在場的朋友,請伸出你的一根手指,大家想想看,一根手指能做什麼呢?能提起一個袋子,能捋下頭髮,扶下眼鏡,摳一下鼻子對吧!但,今天,我要給大家分享:這根手指,如何改變我們的整個生活. 大家看下我手裡的卡包,尤其是女孩子都不陌生吧.銀行卡,購物卡,美容卡,美甲卡,玩具卡...這些都是我老婆一個人的.這麼多卡,太麻煩了.首先,出門不能全帶著吧.今天我想去咖啡店喝咖啡,還要在裡面折騰找一回.還有,在郊區吃了一家新館子,送了張會員卡,下次不知道哪年哪月能來,這

LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

二次联通门 : LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 /* LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 很显然 贪心方程哦不 dp方程为 f[i][j]=f[i-1][j-k*k] 但是这样的话复杂度就是O(N ^ 5) 那么就用bitset优化一下 就ok了 */ #include <iostream> #include <cstdio> #include <bitset> void

Linux 小知识翻译 - 「编译器和解释器」

这次聊聊「编译器和解释器」. 编程语言中,有以C为代表的编译型语言和以Perl为代表的解释型语言.不管是哪种,程序都是以人类能够理解的形式记录的,这种形式计算机是无法理解的. 因此,才会有编译器和解释器. 对于编译型语言,是使用编译器将人类可读的代码转换为机器能够理解的「机器语言」文件,然后通过执行这个「机器语言」文件来实现程序的执行. 另一方面,对于解释型语言,是使用解释器将人类可读的代码逐行解释,一边解释一边执行这个程序.(这里的解释是将代码解释成机器语言,让计算机能够理解) 甚至有的语言既

「每日一歌」微信公众号

最近弄了一个微信公众号,叫做「每日一歌」(微信ID:Song_Daily).每天早上6点,分享一首经典歌曲.欢迎各位来关注! 音乐,广义而言,就是指任何以声音组成的艺术.英文Music一词源于古希腊语的μουσικ?(mousike),意即缪斯(muse)女神的艺术.而中文的音乐二字,许慎<说文解字>解释为“音,声也.生于心,有节于外,谓之音.”认为音乐和声音的区别,在于音乐需要透过人心去想像和创造.音乐可分为创作.演奏.聆听三个过程,在不同文化和社会,对于音乐的过程及其重要性都有不同的理解.

LibreOJ「LibreOJ β Round #4」 游戏

二次联通门 : LibreOJ「LibreOJ β Round #4」 游戏 /* LibreOJ「LibreOJ β Round #4」 游戏 找找规律就会发现.. 当有X的时候,答案跟X个数的奇偶有关 否则就求一下逆序对就好了.. 由于SB的错误..WA了3发才过 然后就签完到走人了 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #defi

LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意

二次联通门 : LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 /* LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 本想打个暴力找找规律 结果交上去就A了... 读入所有数 处理出前缀和 然后枚举区间长度 处理处1~n的答案 后O(1)查询即可 复杂度O(n^2 + m) */ #include <iostream> #include <cstring> #include <cstdio> voi

LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配

#2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 小凸和小方是好朋友,小方给小凸一个 N×M N \times MN×M(N≤M N \leq MN≤M)的矩阵 A AA,要求小凸从其中选出 N NN 个数,其中任意两个数字不能在同一行或同一列,现小凸想知道选出来的 N NN 个数中第 K KK 大的数字的最小值是多少. 输入格式 第一行给出三个整数

一元治愈微信应用的「脸盲症」

「脸盲症」是一种经过正式确认的疾病,全名「面部辨识能力缺乏症」.古装剧里的姑娘戴上面纱少侠就认不出了?下次遇到这种情节别吐槽编剧啦,兴许这位少侠就患有脸盲症呢. 其实在很多方面,计算机软件不止一次吊打了人类,除了最基本的计算.记忆.分析等,这次轮到面部识别能力了- 有些童鞋可能已经知道,现在已经有手机平台实现在自带的相册应用中提供了人脸识别功能,可以自动分析手机里的所有照片,然后将包含同一个人的照片自动分组到一起. 但也许你不知道,这样的功能其实早就有了,而且对于应用开发者来说,甚至不需要自己深