ZROI #365. 【2018普转提day18专题】嘤嘤嘤嘤
2024-08-30 07:42:01
ZROI #365. 【2018普转提day18专题】嘤嘤嘤嘤
直接放代码
具体做法见注释
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k) for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int maxn=5050,maxm=1000100;
int n,m,T;
int ok[maxm],v[maxn],rk[maxm],tv[maxn];
double ans,base,f[maxn][2];
int head[maxn],to[maxn*2],nxt[maxn*2],tot;
void addedge(int x,int y){
to[++tot]=y;nxt[tot]=head[x];head[x]=tot;
to[++tot]=x;nxt[tot]=head[y];head[y]=tot;
}
//f[u][0]表示以u为根的子树内部最大收益
//f[u][1]表示以u为根的子树内部并且有一条链以u为一个端点的最大收益
void dfs(int u,int pa){
f[u][0]=0;f[u][1]=tv[u]-base;
double nw=0;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==pa) continue;
dfs(v,u);
f[u][0]=max(f[u][0]+f[v][0],f[u][1]+f[v][1]+base);
//后一个表示u连向v,并且因为上面减了一次base,v里面减了一次 所以我们得加回来
//这时候经过u的链对于u而言有两条出边
f[u][1]=max(f[u][1]+f[v][0],nw+f[v][1]+tv[u]);
//后一个表示u连向v的收益,即v前面的儿子全都不连向u
//这时候经过u的链对于u而言有一条出边
nw+=f[v][0];
}
f[u][0]=max(nw,max(f[u][0],f[u][1]));
}
bool pd(double x){
base=x;dfs(1,0);
return f[1][0]>=x;
}
int main(){
n=read(),m=read();
rep(i,1,n) v[i]=read(),ok[m-v[i]-1]=1;
rep(i,1,n-1){
int x=read(),y=read();
addedge(x,y);
}
T=read();ok[T]=1;
rep(i,0,T) rk[i]=i;
random_shuffle(rk,rk+1+T);
rep(i,0,T){
int &nw=rk[i];
if(!ok[nw]) continue;
rep(k,1,n){
tv[k]=v[k]+nw;
if(tv[k]>=m) tv[k]-=m;
}
if(!pd(ans)) continue;
double l=ans,r=n*m*1.0/2;
while(r-l>1e-7){
double md=(l+r)/2;
if(pd(md)) l=md,ans=md; else r=md;
}
}
printf("%.7lf\n",ans);
return 0;
}
Review
为什么这么想?
首先是二分答案分数规划,这很显然
关键在于把\(\frac {S} {K+1} \ge Ans\)变成\(S-K \cdot Ans \ge Ans\)
然后就是每选一条链的代价为Ans,并且最终收益大于等于Ans
这样就可以树形dp了
最新文章
- java 多态和内部类
- TCP Provider The semaphore timeout period has expired
- X86 Booting Sequence
- 你写的return null正确吗?
- SpringAOP使用扩展
- JavaScript添加、查找、删除元素的一个实例
- [CLR via C#]25. 线程基础
- Linux系统快速启动方案
- [未完成]关于Oracle知识总结
- Java 对象属性的遍历
- InnoDB的Named File Formats
- 从聚合数据请求菜谱大全接口数据,解析显示到ListView
- JAVA中发送电子邮件的方法
- poj 1562 dfs
- 【Python】 MySQLdb的安装与使用
- jquery-模仿qq提示消息
- java中int算法的有趣现象
- C#打印格式
- mode=";r"; 和 函数末尾调用 regist()!!!!
- [POI2000]病毒 --- AC自动机
热门文章
- 基于sys文件系统的LED驱动的移植【原创】
- ";makefile:5: *** missing separator. Stop.";【转】
- css position弹性盒子测试
- Entityframework连接Mysql遇到的问题
- Loadrunner进行性能测试的步骤
- bind (ERROR 502): bind(0.0.0.0:9501) failed. Error: Address already in use [98] (端口被占用)
- CKEDITOR 默认最大化
- 在CentOs6.x 安装Cx_oracle5.x
- 【linux】lsof命令和{Linux下文件删除、句柄与空间释放问题}
- bzoj 4827 [Hnoi2017] 礼物 —— FFT