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

首先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. Elasticsearch入门,看这一篇就够了

    目录 前言 可视化工具 kibana kibana 的安装 kibana 配置 kibana 的启动 Elasticsearch 入门操作 操作 index 创建 index 索引别名有什么用 删除索 ...

  2. 免费JS甘特图组件dhtmlxgantt

    安装 参考:https://docs.dhtmlx.com/gantt/desktop__install_with_bower.html 可使用NuGet.Bower.npm包管理器安装(应用在asp ...

  3. Python 基础教程 —— Pandas 库常用方法实例说明

    目录 1. 常用方法 pandas.Series 2. pandas.DataFrame ([data],[index])   根据行建立数据 3. pandas.DataFrame ({dic})  ...

  4. Promise解析(待完成)

    Promise是一种异步操作的解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来.避免了多级异步操作的回调函数嵌套. 1.主要用于异步计算 2.可以将异步操作队列化,按 ...

  5. stm32开发笔记(二):stm32系列使用V3.5固件库的帮助文件以及GPIO基本功能(一)

    前言   stm32系列是最常用的单片机之一,不同的版本对应除了引脚.外设.频率.容量等'不同之外,其开发的方法是一样的.  本章讲解使用库函数使用GPIO引脚功能.   补充   本文章为多年前学习 ...

  6. Linux_部署日志服务器

    一.部署日志服务 1.查看自己的系统是否安装(一般默认安装) [root@localhost ~]# rpm -qa | grep rsyslog rsyslog-8.37.0-13.el8.x86_ ...

  7. 说明位图,矢量图,像素,分辨率,PPI,DPI?

    说明位图,矢量图,像素,分辨率,PPI,DPI? 显示全部 关注者 28 被浏览 7,031 关注问题写回答 ​邀请回答 ​添加评论 ​分享 ​     2 个回答 默认排序 刘凯   21 人赞同了 ...

  8. mysql示例及练习2

    #创建数据库并应用create database shopdb;use shopdb;#创建表customerscreate table customers(c_id int primary key ...

  9. stm32中关于NVIC_SetVectorTable函数使用的疑惑与理解

    [转载]2017年12月4日14:48:29 先描述下这几天碰到的一个奇怪的问题: 一个基于stm32的工程中使用到了IAP编程,其中boot空间预留长度为0x6100,实际boot的bin文件大小为 ...

  10. linux服务器环境安全防范教程

    一.目录权限设置很重要:可以有效防范黑客上传木马文件. 如果通过 chmod 644 * -R 的话,php文件就没有权限访问了. 如果通过chmod 755 * -R 的话,php文件的权限就高了. ...