Luogu5405 CTS2019氪金手游(容斥原理+树形dp)
考虑外向树怎么做。显然设f[i][j]为i子树中出现权值和为j的合法方案的概率,转移做树形背包即可。
如果树上只有一条反向边,显然可以先不考虑该边计算概率,再减去将整棵树看做外向树的概率。于是考虑容斥,进一步拓展到多条反向边,就是考虑0条反向边的概率-考虑1条反向边的概率+考虑2条反向边的概率……容斥可以在dp中完成,即遇到反向边时分是否考虑它转移,若考虑乘上-1的系数。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 3010
#define P 998244353
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,a[N][4],p[N],size[N],I[N],ans,t;
int d[N][N],f[N][N],h[N];
bool flag[N];
int ksm(int a,int k)
{
int s=1;
for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
return s;
}
int inv(int a){return ksm(a,P-2);}
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
struct data{int x,y,op;
}e[N];
struct data2{int to,nxt,op;
}edge[N];
void addedge(int x,int y,int op){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].op=op,p[x]=t;}
void dfs(int k)
{
flag[k]=1;
for (int i=1;i<=n;i++)
if (d[k][i]&&!flag[i]) d[k][i]=d[i][k]=k,dfs(i);
}
void dp(int k)
{
f[k][0]=1;
for (int i=p[k];i;i=edge[i].nxt)
{
dp(edge[i].to);
for (int x=size[k];x>=0;x--) h[x]=f[k][x];
for (int x=0;x<=size[k]+size[edge[i].to];x++) f[k][x]=0;
if (edge[i].op==0)
{
for (int x=size[k];x>=0;x--)
for (int y=size[edge[i].to];y>=0;y--)
inc(f[k][x+y],1ll*h[x]*f[edge[i].to][y]%P);
}
else
{
for (int x=size[k];x>=0;x--)
for (int y=size[edge[i].to];y>=0;y--)
inc(f[k][x+y],1ll*(P-1)*h[x]%P*f[edge[i].to][y]%P),
inc(f[k][x],1ll*h[x]*f[edge[i].to][y]%P);
}
size[k]+=size[edge[i].to];
}
for (int x=size[k];x>=0;x--) h[x]=f[k][x];
for (int x=0;x<=size[k]+3;x++) f[k][x]=0;
for (int x=size[k];x>=0;x--)
for (int y=3;y>=1;y--)
inc(f[k][x+y],1ll*h[x]*a[k][y]%P*y*I[x+y]%P);
size[k]+=3;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
for (int i=1;i<=n;i++)
{
for (int j=1;j<=3;j++) a[i][j]=read();
int p=inv(a[i][1]+a[i][2]+a[i][3]);
for (int j=1;j<=3;j++) a[i][j]=1ll*a[i][j]*p%P;
}
for (int i=1;i<n;i++) e[i].x=read(),e[i].y=read(),d[e[i].x][e[i].y]=d[e[i].y][e[i].x]=1;
dfs(1);
for (int i=1;i<n;i++)
{
if (d[e[i].x][e[i].y]==e[i].y) swap(e[i].x,e[i].y),e[i].op=1;
addedge(e[i].x,e[i].y,e[i].op);
}
for (int i=1;i<=n*3;i++) I[i]=inv(i);
dp(1);
for (int i=0;i<=3*n;i++) inc(ans,f[1][i]);
cout<<ans;
return 0;
}
Luogu5405 CTS2019氪金手游(容斥原理+树形dp)的更多相关文章
- P5405-[CTS2019]氪金手游【树形dp,容斥,数学期望】
		
前言 话说在\(Loj\)下了个数据发现这题的名字叫\(fgo\) 正题 题目链接:https://www.luogu.com.cn/problem/P5405 题目大意 \(n\)张卡的权值为\(1 ...
 - [LOJ3124][CTS2019|CTSC2019]氪金手游:树形DP+概率DP+容斥原理
		
分析 首先容易得出这样一个事实,在若干物品中最先被选出的是编号为\(i\)的物品的概率为\(\frac{W_i}{\sum_{j=1}^{cnt}W_j}\). 假设树是一棵外向树,即父亲比儿子先选( ...
 - [LOJ#3119][Luogu5405][CTS2019]氪金手游(DP+容斥)
		
先考虑外向树的做法,显然一个点在其子树内第一个出现的概率等于它的权值除以它子树的权值和.于是f[i][j]表示i的子树的权值和为j时,i子树内所有数的相互顺序都满足条件的概率,转移直接做一个背包卷积即 ...
 - LOJ 3124 「CTS2019 | CTSC2019」氪金手游——概率+树形DP
		
题目:https://loj.ac/problem/3124 看了题解:https://www.cnblogs.com/Itst/p/10883880.html 先考虑外向树. 考虑分母是 \( \s ...
 - [CTS2019]氪金手游
		
[CTS2019]氪金手游 各种情况加在一起 先考虑弱化版:外向树,wi确定 i合法的概率就是wi/sw sw表示子树的w的和,和子树外情况无关 这些概率乘起来就是最终合法的概率 如果都是外向树, f ...
 - LOJ3124 CTS2019 氪金手游 概率、容斥、树形DP
		
传送门 D2T3签到题可真是IQ Decrease,概率独立没想到然后就20pts滚粗了 注意题目是先对于所有点rand一个权值\(w\)然后再抽卡. 先考虑给出的关系是一棵外向树的情况.那么我们要求 ...
 - [CTS2019]氪金手游(容斥+树形背包DP)
		
降智好题.本蒟蒻VP时没想到怎么做被题面迷惑了,只会20分的“好”成绩.简直自闭了. 首先显然度为0的点是白给的,根据等比数列求和公式即可求得.然后考虑这个树如果是一颗外向树,就是每个点先父亲再自己. ...
 - 【题解】Luogu P5405 [CTS2019]氪金手游
		
原题传送门 我们珂以先考虑一条链的情况,设\(sum\)为所有\(w_i\)的总和,\(Sw_i\)表示\(\sum_{j=i}^nw_i\) \[1 \rightarrow 2 \rightarro ...
 - 题解-CTS2019氪金手游
		
Problem \(\mathtt {loj-3124}\) 题意概要:给定 \(n\) 个点,\(w_i\) 分别有 \(p_{i,1},p_{i,2},p_{i,3}\) 的概率取 \(1,2,3 ...
 
随机推荐
- eclipse如何配置tomcat
			
依次点击Window->Show View->Other 找到Server,点击OK,看到控制台旁边已有Server了. 点击server下面的链接,依次选择Apache,根据自己 ...
 - Python Django使用HttpResponse返回图片并显示
			
views.py def read_img(request): """ : 读取图片 :param request: :return: """ ...
 - Class as decorator in python
			
Class as decorator in python . https://www.geeksforgeeks.org/class-as-decorator-in-python/ http://co ...
 - Nginx 配置操作注意事项
			
Nginx reload 会中断现有连接吗? - 知乎https://www.zhihu.com/question/57096250 在NGINX上配置HTTPS---血的教训--要重启NGINX - ...
 - Andorid SQLite数据库开发基础教程(2)
			
Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库.
 - 小D课堂 - 零基础入门SpringBoot2.X到实战_第6节 SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener_24、深入SpringBoot过滤器和Servlet配置过滤器
			
笔记 1.深入SpringBoot2.x过滤器Filter和使用Servlet3.0配置自定义Filter实战(核心知识) 简介:讲解SpringBoot里面Filter讲解和使用Servle ...
 - Dart抽象类和多态
			
/* Dart中抽象类: Dart抽象类主要用于定义标准,子类可以继承抽象类,也可以实现抽象类接口. 1.抽象类通过abstract 关键字来定义 2.Dart中的抽象方法不能用abstract声明, ...
 - shell编程系列23--shell操作数据库实战之mysql命令参数详解
			
shell编程系列23--shell操作数据库实战之mysql命令参数详解 mysql命令参数详解 -u 用户名 -p 用户密码 -h 服务器ip地址 -D 连接的数据库 -N 不输出列信息 -B 使 ...
 - 泡泡一分钟:Semi-Dense Visual-Inertial Odometry and Mapping for Quadrotors with SWAP Constraints
			
张宁 Semi-Dense Visual-Inertial Odometry and Mapping for Quadrotors with SWAP Constraints 具有SWAP约束的四旋翼 ...
 - 数据分析入门——numpy
			
一.什么是numpy Numpy提供了一个在Python中做科学计算的基础库,重在数值计算,主要用于处理多维数组(矩阵)的库.用来存储和处理大型矩阵,比Python自身的嵌套列表结构要高效的多.本身是 ...