LOJ 3124 「CTS2019 | CTSC2019」氪金手游——概率+树形DP
题目:https://loj.ac/problem/3124
看了题解:https://www.cnblogs.com/Itst/p/10883880.html
先考虑外向树。
考虑分母是 \( \sum w \) ,同样一个子树,其实不会因为子树外部分的 \( \sum w \) 不同而对子树内的 DP 值有影响。
比如,在只考虑以子树内的 \( \sum w \) 为分母的情况下做出了 “ cr 子树内部合法的方案数 f[cr] ”
设 \( W' = \sum\limits_{i \in tree_{cr}} w_i \) , \( W = \sum\limits_{i=1}^{n} w_i \)
考虑在以 W 为分母的情况下, cr 子树里的点是 cr 最先出现的概率 \( p = \frac{w_{cr}}{W}\sum\limits_{k=0}^{\infty}(1-\frac{W'}{W})^k = \frac{w_{cr}}{W'} \)
上面的式子就是表示在取到 cr 之前, cr 子树里的点都不能被取到。
注意到只考虑 cr 子树里的点的时候, cr 被第一个取到的概率就是 \( \frac{w_{cr}}{W'} \) !所以可以认为一个子树在总体里的合法概率就是只有这个子树时的合法概率。
所以做 f[ cr ] 的时候可以直接用 f[ v ] 来乘啦!( v 是 cr 的一个孩子)
因为每个点 cr 往 DP 数组里贡献 \( \frac{w_{cr}}{W'} \) ,与一个 W' 有关,所以把 “子树里的 w 和” 记在状态里。
那么 f[ cr ][ j ] 就是把孩子们的 f[ ][ ] 像背包一样合并起来,最后再加入自己的贡献,就是枚举 \( w_{cr} \) ,\( f[cr][j]*p[cr][i]*\frac{i}{j+i} -> f[cr][j+i] \)
这样就是外向树的情况。
有反边,考虑容斥掉。暴力的做法是 2n 枚举哪些反边强制变成正边,那么其余的反边变成 “没有限制” ;如果有 cnt 条反边被强制变成正边,容斥系数就是 ( -1 )cnt 。
考虑不枚举,把系数放在 DP 的过程中。即:每次把一条反边强制变成正边,答案就要乘一个 -1 ;
在转移的时候,遇到反边,把 f[ v ][ * ] 乘上 -1 转移;另一种选择是把 \( \sum\limits_j f[v][j] \) 直接乘到每个 f[cr][ ] 上,f[cr][ ] 的第二维不变,表示该边无限制(无限制的话,\( \frac{w_{cr}}{W'} \) 的 W' 就不应该包含 v 的 \( \sum w \))
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
const int N=,M=N*,mod=;
int upt(int x){while(x>=mod)x-=mod;while(x<)x+=mod;return x;}
int pw(int x,int k)
{int ret=;while(k){if(k&)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=;}return ret;} int n,p[N][],f[N][M],inv[M],siz[N],g[M];
int hd[N],xnt,to[N<<],nxt[N<<]; bool lx[N<<];
void add(int x,int y,bool fx)
{to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;lx[xnt]=fx;}
void dfs(int cr,int fa)
{
f[cr][]=; siz[cr]=; int tp;
for(int i2=hd[cr],v;i2;i2=nxt[i2])
if((v=to[i2])!=fa)
{
dfs(v,cr);
if(lx[i2])//lx[i2] not lx[cr]!!!!!!
{
for(int i=siz[cr];i>=;i--)
{
tp=f[cr][i]; f[cr][i]=;
for(int j=;j<=siz[v];j++)//j=1 is ok
f[cr][i+j]=(f[cr][i+j]+(ll)tp*f[v][j])%mod;
}
}
else
{
int sm=;for(int i=;i<=siz[v];i++)sm=upt(sm+f[v][i]);
for(int i=siz[cr];i>=;i--)
{
tp=f[cr][i]; f[cr][i]=;
for(int j=;j<=siz[v];j++)
f[cr][i+j]=upt(f[cr][i+j]-(ll)tp*f[v][j]%mod);
f[cr][i]=(ll)tp*sm%mod;
}
}
siz[cr]+=siz[v];
}
for(int i=siz[cr];i>=;i--)
{
tp=f[cr][i]; f[cr][i]=;
for(int w=;w<=;w++)
f[cr][i+w]=(f[cr][i+w]+(ll)p[cr][w]*tp%mod*w%mod*inv[i+w])%mod;
}
siz[cr]+=;
}
int main()
{
n=rdn();
for(int i=,a,b,c,s;i<=n;i++)
{
a=rdn();b=rdn();c=rdn();
s=a+b+c; s=pw(s,mod-);
p[i][]=(ll)a*s%mod; p[i][]=(ll)b*s%mod;
p[i][]=(ll)c*s%mod;
}
for(int i=,u,v;i<n;i++)
u=rdn(),v=rdn(),add(u,v,),add(v,u,);
inv[]=;
for(int i=;i<=n*;i++)
inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
dfs(,); int ans=;
for(int i=;i<=siz[];i++)ans=upt(ans+f[][i]);
printf("%d\n",ans);
return ;
}
LOJ 3124 「CTS2019 | CTSC2019」氪金手游——概率+树形DP的更多相关文章
- Loj #3124. 「CTS2019 | CTSC2019」氪金手游
Loj #3124. 「CTS2019 | CTSC2019」氪金手游 题目描述 小刘同学是一个喜欢氪金手游的男孩子. 他最近迷上了一个新游戏,游戏的内容就是不断地抽卡.现在已知: - 卡池里总共有 ...
- 「CTS2019 | CTSC2019」氪金手游 解题报告
「CTS2019 | CTSC2019」氪金手游 降 智 好 题 ... 考场上签到失败了,没想容斥就只打了20分暴力... 考虑一个事情,你抽中一个度为0的点,相当于把这个点删掉了(当然你也只能抽中 ...
- P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】
前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...
- LOJ #3119「CTS2019 | CTSC2019」随机立方体 (容斥)
博客链接 里面有个下降幂应该是上升幂 还有个bk的式子省略了k^3 CODE 蛮短的 #include <bits/stdc++.h> using namespace std; const ...
- LOJ #3119. 「CTS2019 | CTSC2019」随机立方体 组合计数+二项式反演
好神的一道计数题呀. code: #include <cstdio> #include <algorithm> #include <cstring> #define ...
- @loj - 3120@ 「CTS2019 | CTSC2019」珍珠
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有 \(n\) 个在范围 \([1, D]\) 内的整数均匀随机 ...
- [LOJ3124][CTS2019|CTSC2019]氪金手游:树形DP+概率DP+容斥原理
分析 首先容易得出这样一个事实,在若干物品中最先被选出的是编号为\(i\)的物品的概率为\(\frac{W_i}{\sum_{j=1}^{cnt}W_j}\). 假设树是一棵外向树,即父亲比儿子先选( ...
- 「CTS2019」氪金手游
「CTS2019」氪金手游 解题思路 考场上想出了外向树的做法,居然没意识到反向边可以容斥,其实外向树会做的话这个题差不多就做完了. 令 \(dp[u][i]\) 表示单独考虑 \(u\) 节点所在子 ...
- 「CTS2019 | CTSC2019」随机立方体 解题报告
「CTS2019 | CTSC2019」随机立方体 据说这是签到题,但是我计数学的实在有点差,这里认真说一说. 我们先考虑一些事实 如果我们在位置\((x_0,y_0,z_0)\)钦定了一个极大数\( ...
随机推荐
- SparkSQL架构
Spark SQL运行架构 Spark SQL由Core.Catalyst.Hive和Hive-Thriftserver组成 core:负责处理数据的输入/输出,从不同的数据源获取数据(如RDD.Pa ...
- sql片段的定义
<!-- sql片段 id 表示唯一标示 这里不加where是因为 sql片段只对单表查询才抽取出来 这样的重用性更高 --> <sql id="query_user_wh ...
- Manacher(输出最长回文串及下标)
http://acm.hdu.edu.cn/showproblem.php?pid=3294 Girls' research Time Limit: 3000/1000 MS (Java/Others ...
- [BZOJ1604][Usaco2008 Open]Cow Neighborhoods 奶牛的邻居 (Treap+单调队列)
题面 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个"群".每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi( ...
- Java并发编程:线程的创建
Java并发编程:线程的创建 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: #839496;} J ...
- Oracle 汉字占用字节数
在oracle中一个字符特别是中文字符占几个字节是与字符集有关的. 比如GBK,汉字就会占两个字节,英文1个:如果是UTF-8,汉字一般占3个字节,英文还是1个.但是一般情况下,我们都认为是 ...
- 微软Visual Studio Code基本特征
Visual Studio Code它的核心功能还是作为一个代码编辑器.和其他的代码编辑器一样,VScode采取通用的UI和布局,浏览器在左边,显示所有的文件和文件夹,右边你打开的文件的编辑页面. 文 ...
- vue 踩坑之组件传值
Vue 报错[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the pa ...
- [转载]解决Android studio新建项目慢的问题
原文地址为:https://blog.csdn.net/easion_zms/article/details/73181402 Android Studio 好处很多,但是当从github上或者导入其 ...
- Sass Maps的函数-map-remove($map,$key)、keywords($args)
map-remove($map,$key) map-remove($map,$key) 函数是用来删除当前 $map 中的某一个 $key,从而得到一个新的 map.其返回的值还是一个 map.他并不 ...