【模拟7.14】B. 熟练剖分(tree) (概率DP)
一道概率神题,考试时没读清题考完看了学长的玄学题解看了好几个小时
首先f[i][j]表示在点 i 为根的子树中,向下最长轻链长度小于等于 j 的概率。
首先递归下去并求出子树大小,然后枚举重儿子,枚举该点最长轻链长度,再次枚举儿子节点并逐个
假设当前枚举的重儿子是to1,枚举到儿子节点to2,x最长轻链长度为k,设gs为v(to2)之前考虑的儿子中最长轻链长度为k的概率如果v(to1)=v(to2)即v(to2)为重儿子,则设fs为以v(to2)为根的子树最长轻链长度为k的概率:
h[k]=(fs*g[k]%mod+gs*f[to2][k]%mod-gs*fs+mod)%mod;
如果v(to2)是轻儿子,则设fs为以v(to2)为根的子树最长轻链长度为k-1的概率,
h[k]=(fs*g[k]%mod+gs*f[to2][k-1]%mod-gs*fs+mod)%mod;
只是x与to2相连的这条边为轻链所以有减1,值得提醒的一点是这里的f[x][k]并不是最终的f[x][k],只是考虑到当前几个儿子时的值,一个儿子一个儿子地向里加。考虑到f数组直接改的话会错,所以用h数组保存,最后加到g数组中清空h,当to1为重儿子这个情况考虑玩后将g数组加到f中去,清空g。当前节点x求完后,此时的f数组并不是前缀和,所以需要再次转化。
最后求答案时再次将前缀和转化为单个的值
至于此题为啥求概率却用一堆整数想乘是因为题目要求
我们发现每一层的1/chu[x]即为分母,所以可以直接乘逆元,而这样的相加不会影响结果
所以最后i*f[x][i]就是期望。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<string>
5 #include<algorithm>
6 #include<vector>
7 #include<cmath>
8 #include<stack>
9 #include<queue>
10 #define MAXN 3101
11 #define ll long long
12 using namespace std;
13 const ll mod=1e9+7;
14 struct node{ll to,n;}e[MAXN];
15 ll head[MAXN],tot;
16 void add(ll u,ll v){e[++tot].to=v;e[tot].n=head[u];head[u]=tot;}
17 ll size[MAXN];
18 ll f[MAXN][MAXN],g[MAXN],h[MAXN];
19 ll n;ll chu[MAXN];
20 ll pow(ll x,ll y)
21 {
22 ll ans=1;
23 while(y)
24 {
25 if(y&1)ans=(ans*x)%mod;
26 x=(x*x)%mod;
27 y>>=1;
28 }
29 return ans%mod;
30 }
31 void DFS(ll x)
32 {
33 size[x]=1;
34 for(ll i=head[x];i;i=e[i].n)
35 {
36 ll to=e[i].to;
37 DFS(to);
38 size[x]+=size[to];
39 }
40 ll ppow=pow(chu[x],mod-2ll)%mod;
41 for(ll i=head[x];i;i=e[i].n)
42 {
43 for(ll i=0;i<=size[x]+1;++i)g[i]=1;
44 for(ll j=head[x];j;j=e[j].n)
45 {
46 ll fs,gs;
47 ll to1=e[i].to;ll to2=e[j].to;
48 for(ll k=0;k<=size[to2]+1;++k)
49 {
50 if(to1==to2){
51 if(!k)fs=f[to2][k];else fs=f[to2][k]-f[to2][k-1];
52 if(!k)gs=g[k]; else gs=g[k]-g[k-1];
53 h[k]=(fs*g[k]%mod+gs*f[to2][k]%mod-gs*fs+mod)%mod;
54 // printf("h[%lld]=%lld\n",k,h[k]);
55 }
56 else if(k){
57 if(!k)fs=f[to2][k-1];else fs=f[to2][k-1]-f[to2][k-2];
58 if(!k)gs=g[k]; else gs=g[k]-g[k-1];
59 h[k]=(fs*g[k]%mod+gs*f[to2][k-1]%mod-gs*fs+mod)%mod;
60 }
61 }
62 g[0]=h[0];h[0]=0;
63 for(ll k=1;k<=size[to2]+1;++k)
64 {
65 g[k]=(g[k-1]+h[k])%mod;h[k]=0;
66 }
67 }
68 for(ll j=size[x]+1;j>=1;--j)
69 {
70 g[j]=(g[j]-g[j-1]+mod)%mod;//printf("g[%lld]=%lld\n",j,g[j]);
71 }
72 for(ll j=0;j<=size[x]+1;++j)
73 {
74 f[x][j]=(f[x][j]+g[j]*ppow%mod)%mod;
75 // printf("f[%lld][%lld]=%lld\n",x,j,f[x][j]);
76 }
77 // printf("p=%lld\n",pow(chu[x],mod-2ll));
78 }
79 if(head[x]==0)f[x][0]=1;
80 for(ll i=1;i<=size[x]+1;++i)
81 {
82 f[x][i]=(f[x][i]+f[x][i-1]+mod)%mod;
83 // printf("f[%lld][%lld]=%lld\n",x,i,f[x][i]);
84 }
85 }
86 ll ru[MAXN];ll si=1;
87 int main()
88 {
89 scanf("%lld",&n);
90 for(ll i=1;i<=n;++i){
91 scanf("%lld",&chu[i]);
92 for(ll j=1;j<=chu[i];++j){
93 ll y;
94 scanf("%lld",&y);
95 add(i,y);ru[y]++;
96 }
97 }
98 ll root=0;
99 for(ll i=1;i<=n;++i){
100 if(ru[i]==0)
101 root=i;
102 }
103 DFS(root);
104 ll ans=0;
105 for(ll i=1;i<=size[root]+1;++i)
106 {
107 ans=(ans+i*(f[root][i]-f[root][i-1]%mod)+mod)%mod;
108 }
109 printf("%lld\n",(ans+mod)%mod);
110 }
【模拟7.14】B. 熟练剖分(tree) (概率DP)的更多相关文章
- 熟练剖分(tree) 树形DP
熟练剖分(tree) 树形DP 题目描述 题目传送门 分析 我们设\(f[i][j]\)为以\(i\)为根节点的子树中最坏时间复杂度小于等于\(j\)的概率 设\(g[i][j]\)为当前扫到的以\( ...
- 20210501 序列,熟练剖分(tree),建造游乐园(play)
考场 \(65+5+0\),并列 rk2 最高分 \(55+10+10\) T1:等比数列可以写作 \(q^kx\),发现 \(q\le1000\) 且有一档分为 \(a_i\le100\),想到 \ ...
- HZOI2019熟练剖分(tree)
题目大意:https://www.cnblogs.com/Juve/articles/11186805.html 题解: 先给出官方题解: 其实这题跟期望没什么关系,因为E=$\sum_\limits ...
- 【XSY2332】Randomized Binary Search Tree 概率DP FFT
题目描述 \(\forall 0\leq i<n\),求有多少棵\(n\)个点,权值和优先级完全随机的treap的树高为\(i\). \(n\leq 30000\) 题解 设\(f_{i,j}\ ...
- [CSP-S模拟测试]:石头剪刀布(rps)(概率DP)
题目传送门(内部题9) 输入格式 第一行一个整数$n$.接下来$n$行每行$3$个非负整数$r_i,p_i,s_i$. 输出格式 一行一个实数表示答案.当你的答案与标准答案的绝对或相对误差不超过${1 ...
- NOIP模拟测试3「序列·熟练剖分·建造游乐园(play)」
---恢复内容开始--- 序列 刚调出来样例就A了,假装是水题. 因为是乱序,我们要求出来每两项之间最小公比,而不是直接比 求出来每两项之间最小公比,然后扫一遍就完了.(还要注意重复情况) 那么问题就 ...
- 20190716NOIP模拟赛T1 礼物(概率dp+状压)
题目描述 夏川的生日就要到了.作为夏川形式上的男朋友,季堂打算给夏川买一些生 日礼物. 商店里一共有种礼物.夏川每得到一种礼物,就会获得相应喜悦值Wi(每种 礼物的喜悦值不能重复获得). 每次,店员会 ...
- [CSP-S模拟测试]:糊涂图(概率DP)
题目传送门(内部题76) 输入格式 第一行输入三个空格隔开的整数$n,m,s$表示随机加一条边之前的糊涂图的点数,边数,以及起点的编号. 接下来$m$行,每行两个空格隔开的整数$a,b$表示从$a$到 ...
- JZOJ 【NOIP2017提高A组模拟9.14】捕老鼠
JZOJ [NOIP2017提高A组模拟9.14]捕老鼠 题目 Description 为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里的仓库灭灭鼠.于是,猫被农夫约派去捕 ...
随机推荐
- SwiftUI 简明教程之自定义 Modifier
本文为 Eul 样章,如果您喜欢,请移步 AppStore/Eul 查看更多内容. Eul 是一款 SwiftUI & Combine 教程 App(iOS.macOS),以文章(文字.图片. ...
- ARM64平台编译stream、netperf出错解决办法 解决办法:指定编译平台为alpha [root@localhost netperf-2.6.0]# ./configure –build=alpha
ARM64平台编译stream.netperf出错解决办法 http://ilinuxkernel.com/?p=1738 stream编译出错信息: [root@localhost stream]# ...
- 攻防世界(十三)unserialize3
攻防世界系列 :unserialize3 1.打开题目,反序列化 2.代码审计 类xctf被调用时_weakeup()函数会被自动执行,但当序列化字符串中属性值个数大于属性个数,就会导致反序列化异常, ...
- linux中级之ansible配置(roles)
一.roles介绍 什么情况下用到roles? 假如我们现在有3个被管理主机,第一个要配置成httpd,第二个要配置成php服务器,第三个要配置成MySQL服务器.我们如何来定义playbook? 第 ...
- gpgj-19.高级课总结
19.高级课总结 1.高级课最终站 如何对公司估值 找到公司未来的真实盈利*回本年限=估值 如何计算公司未来的盈利 ROIC 资本回报率 零售公司 每平米净现金流 经营面积 高速公路 每 ...
- 几种新的MCU开发环境和语言
https://kuaibao.qq.com/s/20171108A0LQST00?refer=kb_news 桥大学数学科学中心的Damien P. George在研究各种深奥数学.物理问题之余,还 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现
之前有小伙伴在评论区留言说如何集成swagger,最开始没有想透给了对方一个似是而非的回答.实际上后来下来想了一下,用.NET5 提供的Source Generator其实可以很方便的实现接口集成.今 ...
- python实现给字典添加条目的方法
具体实现方法如下: def addWord(theIndex,word,pagenumber): theIndex.setdefault(word, [ ]).append(pagenumber)#存 ...
- Step By Step(userdata)
Step By Step(userdata) 在Lua中可以通过自定义类型的方式与C语言代码更高效.更灵活的交互.这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式.需要说明的 ...
- Step By Step(Lua函数)
Step By Step(Lua函数) 一.函数: 在Lua中函数的调用方式和C语言基本相同,如:print("Hello World")和a = add(x, y).唯一的 ...