码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-08-24 23:05:33      阅读:108      评论:0      收藏:0      [点我收藏+]

标签:freopen   ++i   img   更新   onclick   hide   opened   add   while   

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 }
View Code

 

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

标签:freopen   ++i   img   更新   onclick   hide   opened   add   while   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!