此题niubi!

题目大意:给你一颗n个点的点带权无根树,现在请您进行以下两步操作:

1,选择一个$[0,T]$之间的整数$C$,并令所有的点权$wi$变为$(wi+C)%MOD$

2,选择若干条点不相交的路径;设选择的条数为$k$,覆盖的点的点权和为$S$,则收益为$\frac{S}{k+1}$

请您求出收益最大可能为多少。

数据范围:$T,S≤10^5$,$n≤5000$

我们先不考虑修改点权的过程,只考虑求最大收益应该如何做。

我们显然有一种$O(n^2)$的做法,但是复杂度太高了,加上修改点权的操作就爆炸了,考虑优化。

我们考虑二分这个收益,设当前二分到的收益是$ans$。

假设真实收益大于$ans$,则有:

$\frac{S}{k+1}>ans$

我们进行移项,有:

$S-k\times ans>ans$

这个式子为啥会优秀很多呢?因为$S-k\times ans$可以在$O(n)$的时间内求出了:

我们设$f[u]$表示以$u$为跟的子树内找出了$x$条路径,($x$条路径的和$-x\times ans$)的最大值,且没有路径连出$u$

$g[u]$表示以$u$为跟的子树内找出了$x$条路径,($x$条路径的和$-(x-1)\times ans$)的最大值,有恰好一条路径从$u$连出

我们在以$u$为跟的子树中找出两个儿子$v1$,$v2$,满足$v1$在所有儿子中,$g[v1]-f[v1]$最大,$v2$次大。

设$S=\sum \limits_{v∈son[u]} f[u]$,则有:

$f[u]=max(S,S+(g[v1]-f[v1])+(g[v2]-f[v2]+val[u])-ans)$

$g[u]=max(S,S+(g[v1]-f[v1])+val[u])$

其中$val[u]$表示点$u$的权值。

我们通过二分$ans$,就可以在$O(n\log(-\varepsilon))$确定当前最大的$ans$。

我们考虑点权的修改,一个有效的点权修改方案,需满足至少一个$val[i]$被修改至$MOD-1$,或者增加的值为$T$。

如果每次暴力修改,然后二分查找$ans$,这个复杂度显然是$O(n\log(-\varepsilon))$的,依然会爆炸。

设$Ans[i]$表示当点权被增加了$c[i]$时的$ans$

我们考虑到,一个长度为$n$的随机序列的最长上升子序列期望长度是$O(\log\  n)$的

我们考虑将序列$C$随机打乱

我们先将序列进行修改,然后基于之前求出的$ans$,求一遍答案,判断修改后的序列是否会更加优秀。

如果更加优秀,我们就重新二分出答案。

不难发现,重新二分答案的次数期望是$O(\log\ n)$的。

总的复杂度就是$O(n^2+n\log n\log(-\varepsilon))$的。

完结撒花

 #include<bits/stdc++.h>
#define M 5005
#define eps 1e-6
using namespace std; struct edge{int u,next;}e[M*]={}; int head[M]={},use=;
void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;} double f[M]={},g[M]={},Ans=;
double get(int x){return g[x]-f[x];} int n,MOD,T,val[M]={},Val[M]={}; void dfs(int x,int fa){
int max1=,max2=;
double sumf=;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
int v=e[i].u;
dfs(v,x);
if(get(v)>get(max1)) max2=max1,max1=v;
else if(get(v)>get(max2)) max2=v;
sumf+=f[v];
}
f[x]=max(sumf,sumf+get(max1)+get(max2)+val[x]-Ans);
g[x]=max(max(sumf,sumf+val[x]),sumf+get(max1)+val[x]);
} int cnt=,c[M]={}; bool check(double chg){
Ans=chg;
dfs(,);
return f[]>=chg-eps;
} int main(){
scanf("%d%d",&n,&MOD);
for(int i=;i<=n;i++) scanf("%d",Val+i),Val[i]%=MOD;
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
scanf("%d",&T);
c[++cnt]=; c[++cnt]=T;
for(int i=;i<=n;i++){
c[++cnt]=MOD--Val[i];
if(c[cnt]>T){c[cnt--]=; continue;}
}
memcpy(val,Val,sizeof(val)); random_shuffle(c+,c+cnt+);
double ans=;
for(int hh=;hh<=cnt;hh++){
for(int i=;i<=n;i++) val[i]=(Val[i]+c[hh])%MOD;
if(!check(ans)) continue;
double l=,r=n*MOD/;
while(r-l>eps){
double mid=(l+r)/;
if(check(mid)) l=mid;
else r=mid;
}
ans=max(ans,l);
}
printf("%.10lf\n",ans);
}

【2019北京集训六】路径(path) 二分+DP的更多相关文章

  1. 【2019北京集训3】逻辑 树剖+2-sat

    题目大意:有一颗有$m$个叶子节点的二叉树. 对于叶子节点$i$,$x[i]=(a[i]\ xor\ V_{p[i]})or(b[i]\ xor\ V_{q[i]})$ 对于非叶子节点$i$,$x[i ...

  2. 【2019北京集训测试赛(十三)】数据(sj) 冷静分析

    题目大意:给你一个代表区间$[1,n]$的线段树,问你随机访问区间$[1,n]$中的一个子区间,覆盖到的线段树节点个数的期望(需要乘上$\frac{n(n-1)}{2}$后输出). 数据范围:$n≤1 ...

  3. 【2019北京集训测试赛(七)】 操作 分治+FFT+生成函数

    题目大意:你有$n$个操作和一个初始为$0$的变量$x$. 第$i$个操作为:以$P_i$的概率给$x$加上$A_i$,剩下$1-P_i$的概率给$x$乘上$B_i$. 你袭击生成了一个长度为$n$的 ...

  4. 【2019北京集训2】Elephant 平衡树

    题目大意:给你一个长度为$n$的序列$A_i$,有$q$次操作,每次操作为以下三种之一: 询问区间的$F_M(A_i)$的最大公约数. 区间翻转,区间加一个正数. 我们定义$gcd(0,0)=0$,且 ...

  5. 【2019北京集训2】duck 线段树优化建图+tarjan

    题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和 ...

  6. (2016北京集训十)【xsy1528】azelso - 概率期望dp

    北京集训的题都是好题啊~~(于是我爆0了) 注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了... 设$f_i$表示从$i$出发不回到$i$ ...

  7. 【北京集训D2T3】tvt

    [北京集训D2T3]tvt \(n,q \le 1e9\) 题目分析: 首先需要对两条路径求交,对给出的四个点的6个lca进行分类讨论.易于发现路径的交就是这六个lca里面最深的两个所形成的链. 然后 ...

  8. SVG 学习<八> SVG的路径——path(2)贝塞尔曲线命令、光滑贝塞尔曲线命令

    目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...

  9. SVG 学习<七> SVG的路径——path(1)直线命令、弧线命令

    目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...

随机推荐

  1. Cdnbest的cdn程序默认支持web Socket

    Cdnbest的cdn程序默认支持web Socket    WSS 是 Web Socket Secure 的简称, 它是 WebSocket 的加密版本. 我们知道 WebSocket 中的数据是 ...

  2. tomcat/Java指定加载jar包的路径

    背景:部署的web站点,应用默认加载工程的/webapps/工程名/WEB-INF/lib下的jar包   但是我需要提供一个和web工程没关系的的jar包管理目录   解决方法: 执行java方法时 ...

  3. [leetcode]65. Valid Number 有效数值

    Validate if a given string can be interpreted as a decimal number. Some examples:"0" => ...

  4. [原]OpenStreetMap数据瓦片服务性能篇

    上文说到如何利用node-mapnik架设OpenStreetMap瓦片服务,解决了有没有的问题.然而这个服务还是比较孱弱,主要表现在以下几个方面: 1. Node.js只能使用CPU的一个核,不能有 ...

  5. 浅谈卷积和C++实现

    1 信号处理中的卷积 无论是信号处理.图像处理还是其他一些领域,我们经常会在一些相互关联的数据处理中使用卷积.卷积可以说是算法中一个非常重要的概念.这个概念最早起源于信号处理之中. 假设对于一个线性系 ...

  6. Web常见安全漏洞-SQL注入

    SQL注入攻击(SQL Injection),简称注入攻击,是Web开发中最常见的一种安全漏洞. 可以用它来从数据库获取敏感信息,或者利用数据库的特性执行添加用户,导出文件等一系列恶意操作, 甚至有可 ...

  7. Linux module 添加到bashrc 和临时ifort编译器 以及python2和3的配置

    第一步vim ~/.bashrc按键盘的i然后source /home/export/online1/bjpara/para/modules/scripts/cn-module.sh最后:x! bas ...

  8. leveldb 学习记录(二) Slice

    基本每个KV库都有一个简洁的字符串管理类 比如redis的sds  比如leveldb的slice 管理一个字符串指针和数据长度 通过对字符串指针 长度的管理实现一般的创建 判断是否为空 获取第N个位 ...

  9. 20170805_Elasticsearch_简介和安装

    官网地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html Elk 是一个可高 ...

  10. HBase总结(十一)hbase Java API 介绍及使用示例

    几个相关类与HBase数据模型之间的对应关系 java类 HBase数据模型 HBaseAdmin 数据库(DataBase) HBaseConfiguration HTable 表(Table) H ...