【2019北京集训六】路径(path) 二分+DP
此题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的更多相关文章
- 【2019北京集训3】逻辑 树剖+2-sat
题目大意:有一颗有$m$个叶子节点的二叉树. 对于叶子节点$i$,$x[i]=(a[i]\ xor\ V_{p[i]})or(b[i]\ xor\ V_{q[i]})$ 对于非叶子节点$i$,$x[i ...
- 【2019北京集训测试赛(十三)】数据(sj) 冷静分析
题目大意:给你一个代表区间$[1,n]$的线段树,问你随机访问区间$[1,n]$中的一个子区间,覆盖到的线段树节点个数的期望(需要乘上$\frac{n(n-1)}{2}$后输出). 数据范围:$n≤1 ...
- 【2019北京集训测试赛(七)】 操作 分治+FFT+生成函数
题目大意:你有$n$个操作和一个初始为$0$的变量$x$. 第$i$个操作为:以$P_i$的概率给$x$加上$A_i$,剩下$1-P_i$的概率给$x$乘上$B_i$. 你袭击生成了一个长度为$n$的 ...
- 【2019北京集训2】Elephant 平衡树
题目大意:给你一个长度为$n$的序列$A_i$,有$q$次操作,每次操作为以下三种之一: 询问区间的$F_M(A_i)$的最大公约数. 区间翻转,区间加一个正数. 我们定义$gcd(0,0)=0$,且 ...
- 【2019北京集训2】duck 线段树优化建图+tarjan
题目大意:给你$n$个点,第$i$个点有点权$v_i$.你需要将这$n$个点排成一排,第$i$个点的点权能被累加当且仅当这个点前面存在编号在$[l_i,r_i]$中的点,问你这些点应该如何排列,点权和 ...
- (2016北京集训十)【xsy1528】azelso - 概率期望dp
北京集训的题都是好题啊~~(于是我爆0了) 注意到一个重要的性质就是期望是线性的,也就是说每一段的期望步数可以直接加起来,那么dp求出每一段的期望就行了... 设$f_i$表示从$i$出发不回到$i$ ...
- 【北京集训D2T3】tvt
[北京集训D2T3]tvt \(n,q \le 1e9\) 题目分析: 首先需要对两条路径求交,对给出的四个点的6个lca进行分类讨论.易于发现路径的交就是这六个lca里面最深的两个所形成的链. 然后 ...
- SVG 学习<八> SVG的路径——path(2)贝塞尔曲线命令、光滑贝塞尔曲线命令
目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...
- SVG 学习<七> SVG的路径——path(1)直线命令、弧线命令
目录 SVG 学习<一>基础图形及线段 SVG 学习<二>进阶 SVG世界,视野,视窗 stroke属性 svg分组 SVG 学习<三>渐变 SVG 学习<四 ...
随机推荐
- mybatis 根据参数映射对应模型
ORM 框架的优势在于能让我们利用面向对象的思维去操作数据库, hibernate 作为重量级的 ORM 框架对面向对象的支持很强大.作为半自动化的 mybatis ,对面向对象的支持也是很完备的.这 ...
- python--第十四天总结(js)
选择器允许您对元素组或单个元素进行操作. jQuery 选择器 在前面的章节中,我们展示了一些有关如何选取 HTML 元素的实例. 关键点是学习 jQuery 选择器是如何准确地选取您希望应用效果的元 ...
- 给对话框添加动画 Dialog
先添加一个动画文件(res->anim文件夹中),文件名为a.xml <?xml version="1.0" encoding="utf-8"?&g ...
- spring mvc重定向
spring mvc重定向有三种方法. 1.return new ModelAndView("redirect:/toUrl"); 其中/toUrlt是你要重定向的url. 2.r ...
- [leetcode]77. Combinations组合
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. Example: I ...
- [leetcode]4. Median of Two Sorted Arrays俩有序数组的中位数
There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...
- mybatis进阶--一对多查询
首先,我们还是先给出一个需求:根据订单id查询订单明细——我们知道,一个订单里面可以有多个订单的明细(需求不明确的同学,请留言或者去淘宝网上的订单处点一下就知道了).这个时候,一个订单,对应多个订单的 ...
- Legend 图例
1.添加图例 >>> import matplotlib.pyplot as plt >>> import numpy as np >>> x = ...
- [树状数组+逆序对][NOIP2013]火柴排队
火柴排队 题目描述 涵涵有两盒火柴,每盒装有n根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:∑ (ai-bi)2,i=1,2,3,. ...
- Spring 系列目录
Spring(https://spring.io/) 系列目录 第一篇:Spring 系列 第一章 Spring Core (1) Convert 1.1.1 Spring ConversionSer ...