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 }
View Code
转载于:https://www.cnblogs.com/Wwb123/p/11191427.html
B. 熟练剖分(tree) (概率DP)相关推荐
- 期望/概率dp 学习报告
期望dp 期望的基本性质 离散型随机变量和连续型随机变量 例题1:红包发红包 期望的基本运算性质 例题2:Little Pony and Expected Maximum 期望的一些经典题型 图上期望 ...
- 动态规划报告(树形DP+概率DP
动态规划报告 树形dp 树形 DP,即在树上进行的 DP.由于树固有的递归性质,树形 DP 一般都是递归进行的.一般需要在遍历树的同时维护所需的信息 以一道题目为例 2022CCPC桂林站G Grou ...
- 2018.09.01 poj3071Football(概率dp+二进制找规律)
传送门 概率dp简单题. 设f[i][j]表示前i轮j获胜的概率. 如果j,k能够刚好在第i轮相遇,找规律可以发现j,k满足: (j−1)>>(i−1)(j−1)>>(i−1) ...
- Discovering Gold LightOJ - 1030[概率dp或者记忆化搜索]
题目大意:有一个[1,n][1,n][1,n]的数轴,数轴上的每个对应位置上都有金矿,你初始位置是1,然后你每次都会投色子决定你下一步跳到哪里,如果你跳出了nnn,那么你就要重新投.问你跳到nnn的时 ...
- 【原创】概率DP总结 by kuangbin
概率DP主要用于求解期望.概率等题目. 转移方程有时候比较灵活. 一般求概率是正推,求期望是逆推.通过题目可以体会到这点. 首先先推荐几篇参考的论文: <信息学竞赛中概率问题求解初探> & ...
- poj 3071 Football(概率dp)
http://poj.org/problem? id=3071 大致题意:有2^n个足球队分成n组打比赛.给出一个矩阵a[][],a[i][j]表示i队赢得j队的概率.n次比赛的流程像这样France ...
- HDU 5001 概率DP || 记忆化搜索
2014 ACM/ICPC Asia Regional Anshan Online 给N个点,M条边组成的图,每一步能够从一个点走到相邻任一点,概率同样,问D步后没走到过每一个点的概率 概率DP 測 ...
- hdu 3853 LOOPS 概率DP
简单的概率DP入门题 代码如下: 1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 ...
- HDU - 4035 Maze(概率dp)
题目链接:点击查看 题目大意:给出一个 n 个点的树,初始时位于点 1 ,每个点都会给出一个概率 k[ i ] 和一个概率 e[ i ] ,其代表的意义分别是: k[ i ] :在点 i 有 k[ i ...
最新文章
- 2012-4-2 通过MdiParent设置窗体最前
- 9.9学python靠谱吗-走进小学教材,Python何德何能?9图对比道出真相
- python3 shell 正则表达式 攫取复杂字符串特定子串
- 设置、查看环境变量值
- [SHOI2017]组合数问题
- SQL Server HA - 数据库镜像2 (Mirroring)(1418错误解决)
- [选拔赛1]花园(矩阵快速幂),JM的月亮神树(最短路),保护出题人(斜率优化)
- 数据挖掘实战项目-客户流失及客户行为偏好分析
- python编辑器背景设置为黑色_VScode 配置为Python编辑器
- php 修改密码提示,修改密码通知
- mysql+代码备份,一个很简单的MYSQL数据库备份脚本代码
- c#用控制台程序安装启动停止卸载服务
- Doris FE配置参数(全面)
- Linux CentOS 7 JDK7 Tomcat7 的配置
- python爬取高考各高校分数线查询_python 爬虫 爬取高考录取分数线 信息
- Himall商城文件帮助类IOHelper(1)
- 计算机内部网络连接,在电脑中新建专用网络连接的操作方法【图文教程】
- origin三图合一_神教程:Origin也能玩转图片拼接组合排版
- @SuppressWarnings注解用法详解
- XMind基础教程-主题篇
热门文章
- 在el-table中使用el-popover,没法点击确定或取消来关闭
- Java基础-方法(2)和数组
- 理解cookie和session
- 面试官问:你讲讲分布式事务问题的几种方案?
- 300 行代码带你搞懂 Java 多线程!
- 厉害了,BATJ 必考的 Java 面试题!
- Android --- 调用MediaStore.Images.Media.insertImage保存图片时生成两张图片的问题
- Android --- log.e(),log.d(),log.i()等的区别
- 用html标记语言,HTML标记语言——引用
- ssd3 employee.java_SSD3Panswers icarnegie ssd3的所有答案~十分齐全 - 下载 - 搜珍网