此题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. OpenStack 安装:glance 安装

    接上一篇keystone, 这一篇介绍glance服务: 在开始操作之前,先用source环境变量,然后创建glance 用户,并设置密码为glance [root@linux-node1 ~]#op ...

  2. 在ASP.NET MVC中使用Area区域

    在大型的ASP.NET mvc5项目中一般都有许多个功能模块,这些功能模块可以用Area(中文翻译为区域)把它们分离开来,比如:Admin,Customer,Bill.ASP.NET MVC项目中把各 ...

  3. sonar gitlab+jenkins配置

    sonar.projectKey=test-news-activitysonar.projectName=test-news-activitysonar.projectVersion=$BUILD_N ...

  4. 数组中出现次数超过一半的数字(python)

    题目描述 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. ...

  5. 命名空间 extern的用法 static全局变量

    std是标准库中的命名空间: 关于extern的用法可以参考文献http://blog.163.com/sunjinxia%40126/blog/static/94984879201312145021 ...

  6. Linux磁盘配额

    Step1:修改fstab文件,增加磁盘限额用户和用户组信息 # /etc/fstab# Created by anaconda on Sat Dec 29 04:48:18 2018## Acces ...

  7. java多线程系列15 设计模式 生产者 - 消费者模式

    生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...

  8. Alpha 冲刺 (7/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...

  9. delphi 中record 的类操作符重载简介

    今天简单介绍一下 delphi 中record 的类操作符重载使用,就是如何 实现 record 之间的简单操作. 关于类操作符重载 ,大家可以看官方的文档. Delphi allows certai ...

  10. mui.init()和mui.plusReady()

    1.每个用到mui的页面都调用下mui.init.2.如果需要使用大H5+对象,就写到plusReady中,如plus对象. HTML5+扩展api是针对手机APP的,只有才手机应用(比如手机浏览器) ...