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了

最新文章

  1. java 多态和内部类
  2. TCP Provider The semaphore timeout period has expired
  3. X86 Booting Sequence
  4. 你写的return null正确吗?
  5. SpringAOP使用扩展
  6. JavaScript添加、查找、删除元素的一个实例
  7. [CLR via C#]25. 线程基础
  8. Linux系统快速启动方案
  9. [未完成]关于Oracle知识总结
  10. Java 对象属性的遍历
  11. InnoDB的Named File Formats
  12. 从聚合数据请求菜谱大全接口数据,解析显示到ListView
  13. JAVA中发送电子邮件的方法
  14. poj 1562 dfs
  15. 【Python】 MySQLdb的安装与使用
  16. jquery-模仿qq提示消息
  17. java中int算法的有趣现象
  18. C#打印格式
  19. mode=&quot;r&quot; 和 函数末尾调用 regist()!!!!
  20. [POI2000]病毒 --- AC自动机

热门文章

  1. 基于sys文件系统的LED驱动的移植【原创】
  2. &quot;makefile:5: *** missing separator. Stop.&quot;【转】
  3. css position弹性盒子测试
  4. Entityframework连接Mysql遇到的问题
  5. Loadrunner进行性能测试的步骤
  6. bind (ERROR 502): bind(0.0.0.0:9501) failed. Error: Address already in use [98] (端口被占用)
  7. CKEDITOR 默认最大化
  8. 在CentOs6.x 安装Cx_oracle5.x
  9. 【linux】lsof命令和{Linux下文件删除、句柄与空间释放问题}
  10. bzoj 4827 [Hnoi2017] 礼物 —— FFT