CTS2019 氪金手游
如果所有边都指向根的方向,那么就是要求每个点在子树中所有点之前,
所以考虑子树的\(w_i\)和 和\(w_x\)(\(x\)是子树根),那么概率就是\(\frac{w_x}{\sum w_i}\)
当然\(w_i\)也包含\(w_x\)
这东西可以DP f[x][y]
表示以\(x\)为根,子树\(w_i\)和为\(y\) 满足条件的概率。
如果有反向边,那么容斥是否不满足,如果不满足则为正向边,否则就不管这条边(对子树大小的贡献)
容易看出有\(k\)条反边不满足的贡献是\((-1)^k\),所以就可以直接类似的DP了
code version1:
const int p=998244353;
int a[1005][4];
int fpm(int a,int b){
int c=1;
for(;b;b>>=1,a=a*a%p)if(b&1)c=c*a%p;
return c;
}
int inv[3005];
vector<pii> to[1005];
int f[1005][3005],siz[3005];
int g[3005],h[3005];
int cnt[1005];
void dfs(int x,int fa){
for(auto i:to[x])if(i.x!=fa){
dfs(i.x,x);
}
for(int j=1;j<=3;++j){
int s=0;
g[0]=1;
for(auto i:to[x])if(i.x!=fa){
for(int x=0;x<=s;++x){
if(i.y)h[x]=(h[x]+g[x]*cnt[i.x])%p;
for(int y=0;y<=siz[i.x];++y)
if(i.y)
h[x+y]=(h[x+y]-g[x]*f[i.x][y]%p+p)%p;
else
h[x+y]=(h[x+y]+g[x]*f[i.x][y]%p)%p;
}
for(int x=0;x<=s+siz[i.x];++x){g[x]=h[x];h[x]=0;}
s+=siz[i.x];
}
for(int i=0;i<=s;++i)f[x][i+j]=(f[x][i+j]+g[i]*a[x][j]%p*j*inv[i+j])%p;
chkmax(siz[x],s+j);
}
for(int i=0;i<=siz[x];++i)cnt[x]=(cnt[x]+f[x][i])%p;
}
signed main(){
#ifdef QAQAutoMaton
freopen("fgo.in","r",stdin);
freopen("fgo.out","w",stdout);
#endif
int n;
read(n);
inv[1]=1;
for(int i=2;i<=n*3;++i){
inv[i]=(p-p/i)*inv[p%i]%p;
}
for(int i=1;i<=n;++i){
read(a[i][1]);
read(a[i][2]);
read(a[i][3]);
int w=fpm(a[i][1]+a[i][2]+a[i][3],p-2)%p;
a[i][1]=a[i][1]*w%p;
a[i][2]=a[i][2]*w%p;
a[i][3]=a[i][3]*w%p;
}
int u,v;
for(int i=1;i<n;++i){
read(u,v);
to[u].push_back(make_pair(v,0));
to[v].push_back(make_pair(u,1));
}
dfs(1,0);
int ans=0;
for(int i=0;i<=n*3;++i)ans=(ans+f[1][i])%p;
write(ans,'\n');
return 0;
}
code version2: const int p=998244353;
int a[1005][4];
int fpm(int a,int b){
int c=1;
for(;b;b>>=1,a=a*a%p)if(b&1)c=c*a%p;
return c;
}
int inv[3005];
vector<pii> to[1005];
int f[1005][3005],siz[3005];
int g[3005],h[3005];
int cnt[1005];
void dfs(int x,int fa){
for(auto i:to[x])if(i.x!=fa)dfs(i.x,x);
int s=3;
g[0]=0;
g[1]=a[x][1];
g[2]=a[x][2]*2%p;
g[3]=a[x][3]*3%p;
for(auto i:to[x])if(i.x!=fa){
for(int x=0;x<=s;++x){
if(i.y)h[x]=(h[x]+g[x]*cnt[i.x])%p;
for(int y=0;y<=siz[i.x];++y)
if(i.y)
h[x+y]=(h[x+y]-g[x]*f[i.x][y]%p+p)%p;
else
h[x+y]=(h[x+y]+g[x]*f[i.x][y]%p)%p;
}
for(int x=0;x<=s+siz[i.x];++x){g[x]=h[x];h[x]=0;}
s+=siz[i.x];
}
for(int i=0;i<=s;++i)f[x][i]=g[i]*inv[i]%p;
siz[x]=s;
for(int i=0;i<=siz[x];++i)cnt[x]=(cnt[x]+f[x][i])%p;
}
signed main(){
#ifdef QAQAutoMaton
freopen("fgo.in","r",stdin);
freopen("fgo.out","w",stdout);
#endif
int n;
read(n);
inv[1]=1;
for(int i=2;i<=n*3;++i){
inv[i]=(p-p/i)*inv[p%i]%p;
}
for(int i=1;i<=n;++i){
read(a[i][1]);
read(a[i][2]);
read(a[i][3]);
int w=fpm(a[i][1]+a[i][2]+a[i][3],p-2)%p;
a[i][1]=a[i][1]*w%p;
a[i][2]=a[i][2]*w%p;
a[i][3]=a[i][3]*w%p;
}
int u,v;
for(int i=1;i<n;++i){
read(u,v);
to[u].push_back(make_pair(v,0));
to[v].push_back(make_pair(u,1));
}
dfs(1,0);
int ans=0;
for(int i=0;i<=n*3;++i)ans=(ans+f[1][i])%p;
write(ans,'\n');
return 0;
}