一道概率神题,考试时没读清题考完看了学长的玄学题解看了好几个小时

首先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)的更多相关文章

  1. 熟练剖分(tree) 树形DP

    熟练剖分(tree) 树形DP 题目描述 题目传送门 分析 我们设\(f[i][j]\)为以\(i\)为根节点的子树中最坏时间复杂度小于等于\(j\)的概率 设\(g[i][j]\)为当前扫到的以\( ...

  2. 20210501 序列,熟练剖分(tree),建造游乐园(play)

    考场 \(65+5+0\),并列 rk2 最高分 \(55+10+10\) T1:等比数列可以写作 \(q^kx\),发现 \(q\le1000\) 且有一档分为 \(a_i\le100\),想到 \ ...

  3. HZOI2019熟练剖分(tree)

    题目大意:https://www.cnblogs.com/Juve/articles/11186805.html 题解: 先给出官方题解: 其实这题跟期望没什么关系,因为E=$\sum_\limits ...

  4. 【XSY2332】Randomized Binary Search Tree 概率DP FFT

    题目描述 \(\forall 0\leq i<n\),求有多少棵\(n\)个点,权值和优先级完全随机的treap的树高为\(i\). \(n\leq 30000\) 题解 设\(f_{i,j}\ ...

  5. [CSP-S模拟测试]:石头剪刀布(rps)(概率DP)

    题目传送门(内部题9) 输入格式 第一行一个整数$n$.接下来$n$行每行$3$个非负整数$r_i,p_i,s_i$. 输出格式 一行一个实数表示答案.当你的答案与标准答案的绝对或相对误差不超过${1 ...

  6. NOIP模拟测试3「序列·熟练剖分·建造游乐园(play)」

    ---恢复内容开始--- 序列 刚调出来样例就A了,假装是水题. 因为是乱序,我们要求出来每两项之间最小公比,而不是直接比 求出来每两项之间最小公比,然后扫一遍就完了.(还要注意重复情况) 那么问题就 ...

  7. 20190716NOIP模拟赛T1 礼物(概率dp+状压)

    题目描述 夏川的生日就要到了.作为夏川形式上的男朋友,季堂打算给夏川买一些生 日礼物. 商店里一共有种礼物.夏川每得到一种礼物,就会获得相应喜悦值Wi(每种 礼物的喜悦值不能重复获得). 每次,店员会 ...

  8. [CSP-S模拟测试]:糊涂图(概率DP)

    题目传送门(内部题76) 输入格式 第一行输入三个空格隔开的整数$n,m,s$表示随机加一条边之前的糊涂图的点数,边数,以及起点的编号. 接下来$m$行,每行两个空格隔开的整数$a,b$表示从$a$到 ...

  9. JZOJ 【NOIP2017提高A组模拟9.14】捕老鼠

    JZOJ [NOIP2017提高A组模拟9.14]捕老鼠 题目 Description 为了加快社会主义现代化,建设新农村,农夫约(Farmer Jo)决定给农庄里的仓库灭灭鼠.于是,猫被农夫约派去捕 ...

随机推荐

  1. MongoDB评论管理

    MongoDB简介 文章评论数据分析 相较于一般数据,文章评论一般有如下特点: 数据量巨大.通常评论量要比帖子.文章大很多 写入操作频繁. 价值较低.一般来说,我们的主要目标还是在帖子(文章)本身. ...

  2. springboot使用jwt进行权限验证

    springboot使用jwt进行权限验证 依赖准备 首先导入对应的依赖 <dependencies> <dependency> <groupId>org.apac ...

  3. FastDFS依赖无法导入

    FastDFS依赖无法导入 fastdfs-client-java 导入爆红 <!-- FastDFS--> <dependency> <groupId>org.c ...

  4. [物联网] 电气 & 工控

    原理 一次回路和二次回路 一次回路:强电部分(380伏---22万伏),连接发电机.电动机.变压器.电网线路.电网开关.电网避雷器等等 二次回路:弱电部分,指的是控制线路.保护线路.测量线路.计量线路 ...

  5. [刷题] PTA 7-32 说反话-加强版

    题目描述: 给定一个英语句子,各个单词之间用空格分隔.要求编写程序,将所有单词倒序输出 输入示例: Hello World Here I Come 输出示例: Come I Here World He ...

  6. [Linux] Linux C编程一站式学习 Part.2

    C语言本质 计算机中数的表示 浮点数:符号位+指数部分(2的多少次方)+尾数部分(小数点后的数字) 用偏移的指数(Biased Exponent)表示负指数 正规化(Normalize):尾数部分最高 ...

  7. 【转载】使用rdp协议访问远程Linux桌面

    使用rdp协议访问远程Linux桌面 2017年03月31日 16:23:49 太阳之影 阅读数:2169   一般情况下,如果需要登陆远程Linux系统,我们会使用ssh/telnet来完成,如果需 ...

  8. Django/Flask的一些实现方法

    一.导出当前项目用到的依赖到requirements.txt文件中 pip freeze > requirements.txt 二.安装当前项目需要的依赖: pip install -r req ...

  9. Zabbix 自动发现并监控磁盘IO、报警 引言

    引言 Zabbix并没有提供模板来监控磁盘的IO性能,所以我们需要自己来创建一个,由于一台服务器中磁盘众多,如果只有一两台可以手动添加,但服务集群达到几十那就非常麻烦,因此需要利用自动发现这个功能,自 ...

  10. 【例 3】 修改 bols 文件的 atime 和 mtime。 [root@localhost ~]# touch -d "2017-05-04 15:44" bols

    Linux touch命令:创建文件及修改文件时间戳 < Linux删除空目录(rmdir命令)Linux在文件之间建立软/硬链接(ln命令) > <Linux就该这么学>是一 ...