【xsy1130】tree 树形dp+期望dp
题目写得不清不楚的。。。
题目大意:给你一棵$n$个节点的树,你会随机选择其中一个点作为根,随后随机每个点深度遍历其孩子的顺序。
下面给你一个点集$S$,问你遍历完$S$中所有点的期望时间,点集S中的点可能会重复。
数据范围:$n≤10^5$
我们考虑钦定根,然后暴力$dp$。
设$s[u]$表示遍历以$u$为根的子树的耗时。
设$f[u]$表示开始遍历子树$u$,且最后遍历在子树$u$中结束的期望耗时。
不难发现,$s[u]=2\times siz[u]-2$,其中$siz[u]$为以$u$为根的子树的节点个数。
对于$u$的孩子,我们把它们分成黑点和白点两类,其中黑点v代表以v为根的子树内包含有集合$S$中的点,白点代表不包含有集合$S$中的点。
对于任意一种遍历顺序而言,遍历特征如图所示:
显然,$b_m$后的节点是不需要遍历的。
设我们总共有$m$个黑点,则有:
$f[u]=\dfrac{m-1}{m}\sum\limits_{col[v]=black}s[v]+\dfrac{1}{m}\sum\limits_{col[v]=black}(f[v]+1)+\dfrac{m}{m+1}\sum\limits_{col[v]=white}s[v]$
此处的$v$必须满足是$u$的儿子。
我们通过这个$O(n^2)$的暴力转移就可以获得70分的好成绩。
考虑满分做法,我们以$1$为根执行一次$dfs$,求出所有点的f值和s值。
我们进行第二次$dfs$,在$dfs$的过程中维护u的父亲的F值。
然后套入刚刚的公式中去求即可。
复杂度就降低到了$O(n)$
#include<bits/stdc++.h>
#define M 1005
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;} int siz[M]={},n,S,is[M]={},ok[M]={};
double s[M]={},f[M]={}; void dfs(int x,int fa){
siz[x]=; ok[x]=is[x];
int m=;
double sumb=,sumf=,sumw=;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
dfs(e[i].u,x);
siz[x]+=siz[e[i].u];
ok[x]+=ok[e[i].u];
if(ok[e[i].u]){
m++;
sumb+=s[e[i].u];
sumf+=f[e[i].u]+;
}else{
sumw+=s[e[i].u];
}
}
s[x]=*siz[x];
if(m){
f[x]=sumb*(m-)/m+sumf/m+sumw*m/(m+);
}
} int main(){
scanf("%d",&n);
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
scanf("%d",&S);
for(int i=,x;i<=S;i++) scanf("%d",&x),is[x]=;
double ans=;
for(int i=;i<=n;i++){
memset(ok,,sizeof(ok));
memset(siz,,sizeof(siz));
memset(s,,sizeof(s));
memset(f,,sizeof(f));
dfs(i,);
ans+=f[i];
}
printf("%.10lf\n",ans/n);
}
放一个暴力
这是正解:
#include<bits/stdc++.h>
#define M 100005
#define D double
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;} int siz[M]={},n,S,is[M]={},ok[M]={};
D s[M]={},f[M]={},ans=; void dfs(int x,int fa){
siz[x]=; ok[x]=is[x];
int m=;
D sumb=,sumf=,sums=;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
dfs(e[i].u,x);
siz[x]+=siz[e[i].u];
ok[x]+=ok[e[i].u];
if(ok[e[i].u]){
m++;
sumb+=s[e[i].u];
sumf+=f[e[i].u]+;
}else{
sums+=s[e[i].u];
}
}
s[x]=*siz[x];
if(m){
f[x]=sumb*(m-)/m+sumf/m+sums*m/(m+);
}
}
void dfs(int x,int fa,D F){
int OK=S-ok[x],m=bool(OK);
D sumb=,sumf=,sums=;
if(m) sumf+=F,sumb+=*(n-siz[x]); else sums+=*(n-siz[x]);
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
if(ok[e[i].u]) m++,sumb+=s[e[i].u],sumf+=f[e[i].u]+;
else sums+=s[e[i].u];
}
D res=; if(m) res=sumb*(m-)/m+sumf/m+sums*m/(m+);ans+=res;
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
if(ok[e[i].u]){
m--; sumb-=s[e[i].u]; sumf-=f[e[i].u]+;
if(m) F=sumb*(m-)/m+sumf/m+sums*m/(m+); else F=;
m++; sumb+=s[e[i].u]; sumf+=f[e[i].u]+;
}else{
sums-=s[e[i].u];
if(m) F=sumb*(m-)/m+sumf/m+sums*m/(m+); else F=;
sums+=s[e[i].u];
}
dfs(e[i].u,x,F+);
}
} int main(){
scanf("%d",&n);
for(int i=,x,y;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
scanf("%d",&S); int SS=;
for(int i=,x;i<=S;i++) scanf("%d",&x),SS+=(is[x]==),is[x]=;
dfs(,); S=SS;
dfs(,,);
printf("%.10lf\n",ans/n);
}
【xsy1130】tree 树形dp+期望dp的更多相关文章
- [CF697D]Puzzles 树形dp/期望dp
Problem Puzzles 题目大意 给一棵树,dfs时随机等概率选择走子树,求期望时间戳. Solution 一个非常简单的树形dp?期望dp.推导出来转移式就非常简单了. 在经过分析以后,我们 ...
- 概率dp+期望dp 题目列表(一)
表示对概率和期望还不是很清楚定义. 目前暂时只知道概率正推,期望逆推,然后概率*某个数值=期望. 为什么期望是逆推的,例如你求到某一个点的概率我们可以求得,然后我们只要运用dp从1~n每次都加下去就好 ...
- BZOJ1076/Luogu2473 奖励关(SCOI2008)状压DP+期望DP
题意:给n(n<=15)种宝物宝物有价值w且每个宝物有一个前置宝物(即你必须先吃过它的所有前置宝物至少一次才能吃该宝物),共有m轮游戏,每一轮会在n种宝物等概率选一个出来,因为宝物价值可正可负你 ...
- BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】
题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...
- [思路题][LOJ2290][THUWC2017]随机二分图:状压DP+期望DP
分析 考虑状压DP,令\(f[sta]\)表示已匹配状态是\(sta\)(\(0\)代表已匹配)时完美匹配的期望数量,显然\(f[0]=1\). 一条边出现了不代表它一定在完美匹配内,这也导致很难去直 ...
- BZOJ1076: [SCOI2008]奖励关【状压DP+期望DP】
Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物, 每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的 ...
- B1076 [SCOI2008]奖励关 状压dp&&期望dp
这个题的n<15,一看就是状压dp.但是状态不是很好想.f[][]存i关的状态j. 这个题另一个关键思想在于倒推,我一开始想的是正推,但是只能记忆化了. 题干: 题目描述 你正在玩你最喜欢的电子 ...
- CF482C Game with Strings (状压DP+期望DP)
题目大意:甲和乙玩游戏,甲给出n(n<=50)个等长的字符串(len<=20),然后甲选出其中一个字符串,乙随机询问该字符串某一位的字符(不会重复询问一个位置),求乙能确定该串是哪个字符串 ...
- Problem Arrangement ZOJ - 3777(状压dp + 期望)
ZOJ - 3777 就是一个入门状压dp期望 dp[i][j] 当前状态为i,分数为j时的情况数然后看代码 有注释 #include <iostream> #include <cs ...
随机推荐
- php-fpm 的 pm.start_servers 参数调整
大家注意一下 在 php-fpm 的配置文件中, pm.start_servers 必须是介于 pm.min_spare_servers 和 pm.max_spare_servers 这个值之间 ...
- [转]图解CSS的padding,margin,border属性(详细介绍及举例说明)
图解CSS的padding,margin,border属性 W3C组织建议把所有网页上的对像都放在一个盒(box)中,设计师可以通过创建定义来控制这个盒的属性,这些对像包括段落.列表.标题.图片以及层 ...
- 创建视图&新建表按照视图结构
create view V_tableTemp as select a.* from TEMPCLIENT a ,TEMPCLIENTSTUFF b where a.CORNO<>' ...
- linux 安装 ORACLE JDK 8
1.卸载默认的OPENJDK 查看 open jdk 的安装 rpm -qa | grep java 卸载 openjdk rpm -e --nodeps java-1.7.0-openjdk-1.7 ...
- telnet 命令使用方法详解,telnet命令怎么用
telnet 命令使用方法详解,telnet命令怎么用? 文章类型:电脑教程 原创:天诺时空 什么是Telnet? 对于Telnet的认识,不同的人持有不同的观点,可以把Telnet当成一种通信协 ...
- Mybatis-Plus 实战完整学习笔记(十一)------条件构造器删除,修改,conditon
1.修改功能--其他过滤方式跟select一样 /** * 修改条件构造器 * @throws SQLException */ @Test public void selectUpdate() thr ...
- javaWeb的验证码编写
一.前言 验证码可以说在我们生活中已经非常普遍了,任何一个网站,任何一个App都会有这个功能,但是为啥要有这个呢?如何做才能做出来呢?下面小编会带领大家一起用java完成一个验证码的功能. 二.验证码 ...
- R语言的文件写入
R语言的文件写入 官方文档介绍如下: write.table(x, file = "", append = FALSE, quote = TRUE, sep = " &q ...
- javascript的Mixins
mixin在javascript里可以看作是一种从别的对象"借用"功能的方法.每一个新定义的对象都有一个 prototype属性,其他的对象就可以从这里"借用" ...
- 20170831工作日记--自定义View学习
学习了LayoutInflater的原理分析.视图的绘制流程.视图的状态及重绘等知识,按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件.组合控件.以及继承控件.那么下面我们就来依次 ...