题解-CTS2019氪金手游
Problem
题意概要:给定 \(n\) 个点,\(w_i\) 分别有 \(p_{i,1},p_{i,2},p_{i,3}\) 的概率取 \(1,2,3\)。
在确定了所有的 \(w_i\) 后再开始游戏:不断抽点,点 \(i\) 被抽中的概率为 \(\frac {w_i}{\sum_{j=1}^nw_j}\),直到所有点都被抽中过。
给定 \(n-1\) 个二元组 \((u,v)\) 表示第一次抽中 \(u\) 的时间需要比第一次抽中 \(v\) 的时间早,且若将这 \(n-1\) 个二元组中的两个元素连无向边,则这张图是一棵树。
问满足所有二元组限制的概率。
\(n\leq 1000\)
Solution
(话说考场上看错了题,以为是确定好每个点抽中的概率后再进行游戏,打了正解加仨暴力,跑出来都是一样的就是和大样例不一样,导致心态崩了 而且题面里并没有提到这个区别)
这题的解题突破口在于这个题的限制是一棵树,但边的方向不唯一(没法找到根使得这棵树变成内向树或外向树)
为了解题方便,不妨设这棵树是以 \(1\) 号节点为根的外向树(对于每条边而言,方向都是从靠近 \(1\) 的一端指向远离 \(1\) 的一端)
那么可以发现,\(1\) 号节点必须是最后一个抽到的,概率为 \(\frac {w_1}{\sum_{i=1}^nw_i}\),而且只要满足这个条件后,这个点就没有用了,问题分解成 \(1\) 的每棵子树满足自身拓扑序的概率之积,这又是一个子问题
设 \(sz_i\) 表示 \(i\) 的子树中概率系数的和(\(\sum_{v\in subtree(x)}w_v\))
即设 \(f[x]\) 表示 \(x\) 的子树内满足拓扑序的概率,则 \(f[x]=\frac {w_x}{sz_x}\prod_{x\rightarrow v}f[v]\),不难得到 \(Ans=f[1]=\prod_{x=1}^n\frac {w_x}{sz_x}\)
那么可以用一个Dp解决这个问题:设 \(f[x][i]\) 表示在 \(i\) 的子树中、概率系数和为 \(j\) 且满足拓扑序的概率,\(O(n^2)\)
毒瘤出题人居然不给这档部分分?
考虑到这棵树不是外向树,存在若干条内向边。
直接处理内向边不好处理,现在存在一种方法,即用 “不考虑这条边”的方案数 减去 “考虑这条边为外向边”的方案数
(用图来表达即:\(o\rightarrow o\leftarrow o\) 等于 \(o\rightarrow o\quad o\) 减去 \(o\rightarrow o\rightarrow o\))
然后在树上Dp时,遇到此类内向边就将权值用上面这种方法计算一下即可。
听说这题还有另一种做法,代码实现上是一样的,但思想不大一样:
考虑设 \(g[i]\) 表示这若干条内向边中,至少有 \(i\) 条内向边的条件不满足,则容斥可知答案为:\(\sum_i(-1)^ig[i]\)
而 “至少 \(i\) 条内向边不满足”,也即 “\(i\) 条内向边变为外向边,而其他内向边断开”
这样在Dp的时候加入一个容斥系数即可:一开始设所有内向边断开,然后给其加上一个负的 “内向边变外向边” 的权值
Code
//loj-3124
#include <cstdio>
typedef long long ll;
const int N = 1013, p = 998244353;
struct Edge {int v, w, nxt;} a[N<<1];
int head[N], sz[N];
int a1[N], a2[N], a3[N];
int F[N][N*3], arr[N*3];
int inv[N*3], n, _;
inline int qpow(int A, int B) {
int res = 1; while(B) {
if(B&1) res = (ll)res * A%p;
A = (ll)A * A%p, B >>= 1;
} return res;
}
void dfs(int x, int las) {
int*f = F[x];
f[0] = 1;
for(int ii=head[x],v;ii;ii=a[ii].nxt)
if((v=a[ii].v) != las) {
dfs(v, x);
int*g = F[v];
const int sx = sz[x] * 3, sv = sz[v] * 3;
for(int i=0;i<=sx+sv;++i) arr[i] = 0;
if(!a[ii].w)
for(int i=0;i<=sx;++i)
for(int j=0;j<=sv;++j)
arr[i+j] = (arr[i+j] + (ll)f[i] * g[j])%p;
else {
ll sm = 0;
for(int i=0;i<=sv;++i) sm += g[i];
sm %= p;
for(int i=0;i<=sx;++i) arr[i] = sm * f[i]%p;
for(int i=0;i<=sx;++i)
for(int j=0;j<=sv;++j)
arr[i+j] = (arr[i+j] - (ll)f[i] * g[j] + (ll)p*p)%p;
}
for(int i=0;i<=sx+sv;++i) f[i] = arr[i];
sz[x] += sz[v];
}
const int sx = sz[x] * 3;
for(int i=0;i<=sx+3;++i) arr[i] = 0;
for(int i=0;i<=sx;++i) {
arr[i+1] = (arr[i+1] + (ll)f[i] * a1[x]%p * inv[i+1])%p;
arr[i+2] = (arr[i+2] + (ll)f[i] * a2[x]%p * inv[i+2] * 2)%p;
arr[i+3] = (arr[i+3] + (ll)f[i] * a3[x]%p * inv[i+3] * 3)%p;
}
for(int i=0;i<=sx+3;++i) f[i] = arr[i];
++sz[x];
}
int main() {
scanf("%d",&n);
inv[0] = inv[1] = 1;
for(int i=2;i<=n*3;++i) inv[i] = (ll)(p-p/i) * inv[p%i]%p;
for(int i=1;i<=n;++i) {
scanf("%d%d%d",a1+i,a2+i,a3+i);
ll v = qpow(a1[i] + a2[i] + a3[i], p-2);
a1[i] = v * a1[i]%p;
a2[i] = v * a2[i]%p;
a3[i] = v * a3[i]%p;
}
for(int i=1,x,y;i<n;++i) {
scanf("%d%d",&x,&y);
a[++_].v = y, a[_].w = 0, a[_].nxt = head[x], head[x] = _;
a[++_].v = x, a[_].w = 1, a[_].nxt = head[y], head[y] = _;
}
dfs(1, 0);
ll Ans = 0;
for(int i=sz[1]*3;~i;--i)
Ans += F[1][i];
printf("%lld\n", Ans%p);
return 0;
}
题解-CTS2019氪金手游的更多相关文章
- [CTS2019]氪金手游
[CTS2019]氪金手游 各种情况加在一起 先考虑弱化版:外向树,wi确定 i合法的概率就是wi/sw sw表示子树的w的和,和子树外情况无关 这些概率乘起来就是最终合法的概率 如果都是外向树, f ...
- 【题解】Luogu P5405 [CTS2019]氪金手游
原题传送门 我们珂以先考虑一条链的情况,设\(sum\)为所有\(w_i\)的总和,\(Sw_i\)表示\(\sum_{j=i}^nw_i\) \[1 \rightarrow 2 \rightarro ...
- LOJ3124 CTS2019 氪金手游 概率、容斥、树形DP
传送门 D2T3签到题可真是IQ Decrease,概率独立没想到然后就20pts滚粗了 注意题目是先对于所有点rand一个权值\(w\)然后再抽卡. 先考虑给出的关系是一棵外向树的情况.那么我们要求 ...
- [LOJ#3119][Luogu5405][CTS2019]氪金手游(DP+容斥)
先考虑外向树的做法,显然一个点在其子树内第一个出现的概率等于它的权值除以它子树的权值和.于是f[i][j]表示i的子树的权值和为j时,i子树内所有数的相互顺序都满足条件的概率,转移直接做一个背包卷积即 ...
- Luogu5405 CTS2019氪金手游(容斥原理+树形dp)
考虑外向树怎么做.显然设f[i][j]为i子树中出现权值和为j的合法方案的概率,转移做树形背包即可. 如果树上只有一条反向边,显然可以先不考虑该边计算概率,再减去将整棵树看做外向树的概率.于是考虑容斥 ...
- p5405 [CTS2019]氪金手游
题目大意 题意狗屁不通 看毛子语都比看这个题面强 分析 我们假设这棵树是一个内向树 那么我们可以轻易的得到dp[x][i]表示x点子树和为i的期望 转移只需枚举当前期望大小和子树期望大小即可 但是由于 ...
- [CTS2019]氪金手游(容斥+树形背包DP)
降智好题.本蒟蒻VP时没想到怎么做被题面迷惑了,只会20分的“好”成绩.简直自闭了. 首先显然度为0的点是白给的,根据等比数列求和公式即可求得.然后考虑这个树如果是一颗外向树,就是每个点先父亲再自己. ...
- 【CTS2019】氪金手游(动态规划)
[CTS2019]氪金手游(动态规划) 题面 LOJ 洛谷 题解 首先不难发现整个图构成的结构是一棵树,如果这个东西是一个外向树的话,那么我们在意的只有这棵子树内的顺序关系,子树外的关系与这棵子树之间 ...
- Loj #3124. 「CTS2019 | CTSC2019」氪金手游
Loj #3124. 「CTS2019 | CTSC2019」氪金手游 题目描述 小刘同学是一个喜欢氪金手游的男孩子. 他最近迷上了一个新游戏,游戏的内容就是不断地抽卡.现在已知: - 卡池里总共有 ...
随机推荐
- JS实现文字向上无缝滚动轮播
效果图: 全部代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- Faster, more memory efficient and more ordered dictionaries on PyPy
Faster, more memory efficient and more ordered dictionaries on PyPy https://morepypy.blogspot.com/20 ...
- markdown如何在表格内换行?
答:使用<br>即可在表格内换行
- textEdit
textEdit可以添加背景图片.渐变色.文字颜色.大小等等 <?xml version="1.0" encoding="utf-8"?> < ...
- 从0开始学爬虫4之requests基础知识
从0开始学爬虫4之requests基础知识 安装requestspip install requests get请求:可以用浏览器直接访问请求可以携带参数,但是又长度限制请求参数直接放在URL后面 P ...
- 0010.Regular Expression Matching(H)
jjc . Regular Expression Matching(hard) Given an input string (s) and a pattern (p), implement regul ...
- 【计算机视觉】OpenCV篇(5) - 仿射变换与透视变换
参考: 图像处理的仿射变换与透视变换(https://www.imooc.com/article/27535) http://ex2tron.wang/opencv-python-extra-warp ...
- springboot中使用mybatis的分页插件pageHelper
首先在pom.xml中配置 <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot ...
- 小程序 支持html富文本吗
详见: https://www.jianshu.com/p/9b9b97b17393
- JavaScript图形实例:图形的扇形变换和环形变换
1.1 扇形变换 将如图1所示的上边长方形的图形变换为下边的扇形图形的变换称为扇形变换. 设长方形图形中任一点P1(X1,Y1)变换为扇形图形上的点P2(X2,Y2),长方形的长为X,扇形圆心坐标为 ...