【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 ...
随机推荐
- Linux---CentOS 定时运行脚本配置
很多时候我们有希望服务器定时去运行一个脚本来触发一个操作,比如使用七牛的工具上传,如果同步文件里面有新增加一个文件,这个时候我们可以提供定时脚本去完成我们需要的同步命令(七牛的qrsbox工具是自动会 ...
- 2018.11.24 poj3415Common Substrings(后缀数组+单调栈)
传送门 常数实在压不下来(蒟蒻开O(3)都过不了). 但有正确性233. 首先肯定得把两个字符串接在一起. 相当于heightheightheight数组被height<kheight<k ...
- (12)We should aim for perfection — and stop fearing failure
https://www.ted.com/talks/jon_bowers_we_should_aim_for_perfection_and_stop_fearing_failure/transcrip ...
- Python里的拷贝
可变数据类型:list.dict 不可变数据类型:int.float.string.tuple 引用 https://github.com/taizilongxu/interview_python#4 ...
- vim 查找替换批量替换
一.vi查找: 当你用vi打开一个文件后,因为文件太长,如何才能找到你所要查找的关键字呢?在vi里可没有菜单-〉查找, 不过没关系,你在命令模式下敲斜杆(/)这时在状态栏(也就是屏幕左下脚)就出 ...
- 深入浅出javascript(五)函数
全局函数 自定义函数 函数对象 函数的属性和方法 一.全局函数 全局函数不同于内置对象的方法(来源于网络),一共有7个,可以直接使用. escape( ).eval( ).isFinite( ).is ...
- 知识点:定义input type=file 样式的方法(转)
——“当我们想要用css美化表单的时候,有两个控件就会和前段人员作对,一个是是大名鼎鼎的select,另一个就是我现在要说说的 input type=file” 为什么要美化file控件?试想一下,别 ...
- sublime text配置node.js调试
1. 首先到 nodejs.org 下载 Node.js 安装包并安装.2. 打开 Sublime Text 2 编辑器.选择菜单 Tools --> Build System --> n ...
- POJ3020 Antenna Placement
Antenna Placement Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9586 Accepted: 4736 ...
- 编写Shell脚本
1.脚本的编写 Shell脚本本身是一个文本文件,这里编写一个简单的程序,在屏幕上显示一行helloworld! 脚本内容如下: #!/bin/bash #显示“Hello world!" ...