题目大意
题意狗屁不通
看毛子语都比看这个题面强
分析
我们假设这棵树是一个内向树
那么我们可以轻易的得到dp[x][i]表示x点子树和为i的期望
转移只需枚举当前期望大小和子树期望大小即可
但是由于边的方向不一定
所以这棵树上存在反向边
我们可以容斥有i个边不合法的情况
因此对于一个反向边要么x点加上关系合法,将子树分离的贡献
要么这个边算是不合法的
对于这种情况我们可以直接减掉贡献
因为我们知道这个贡献已经是0~i的容斥情况
而这个减号相当于*-1
可以完成容斥
复杂度O(n^2)
代码
#include<bits/stdc++.h> using namespace std; #define fi first #define se second #define pb push_back #define mp make_pair const int mod = 998244353; int dp[1100][3300],n,m,inv[3300],res[3300],siz[1100]; vector<pair<int,int> >v[1100]; inline int pw(int x,int p){ int ans=1; while(p){ if(p&1)ans=1ll*ans*x%mod; x=1ll*x*x%mod; p>>=1; } return ans; } inline void dfs(int x,int fa){ siz[x]=1; for(int i=0;i<v[x].size();i++) if(v[x][i].fi!=fa){ int y=v[x][i].fi,z=v[x][i].se; dfs(y,x); for(int j=0;j<=3*siz[x];j++) for(int k=0;k<=3*siz[y];k++){ int sum=1ll*dp[x][j]*dp[y][k]%mod; if(z)res[j+k]=(res[j+k]+sum)%mod; else res[j+k]=(res[j+k]-sum+mod)%mod,res[j]=(res[j]+sum)%mod; } siz[x]+=siz[y]; for(int j=0;j<=3*siz[x];j++)dp[x][j]=res[j],res[j]=0; } for(int i=0;i<=3*siz[x];i++)dp[x][i]=1ll*dp[x][i]*inv[i]%mod; } int main(){ int i,j,k,ans=0; scanf("%d",&n); for(i=1;i<=n;i++){ int x,y,z,iv; scanf("%d%d%d",&x,&y,&z); iv=pw(x+y+z,mod-2); dp[i][1]=1ll*x*iv%mod; dp[i][2]=2ll*y*iv%mod; dp[i][3]=3ll*z*iv%mod; } for(i=1;i<n;i++){ int x,y; scanf("%d%d",&x,&y); v[x].pb(mp(y,1)); v[y].pb(mp(x,0)); } inv[0]=inv[1]=1; for(i=2;i<=3*n;i++)inv[i]=pw(i,mod-2); dfs(1,0); for(i=0;i<=3*n;i++)ans=(ans+dp[1][i])%mod; printf("%d\n",ans); return 0; }