【CTS2019】氪金手遊(動態規劃)

【CTS2019】氪金手遊(動態規劃)

題面

LOJ
洛谷ios

題解

首先不難發現整個圖構成的結構是一棵樹,若是這個東西是一個外向樹的話,那麼咱們在乎的只有這棵子樹內的順序關係,子樹外的關係與這棵子樹之間的限制無關。因此咱們只須要強制根節點在其餘兒子以前的就好了(你能夠認爲若是此次隨機抽到了子樹外面的東西就從新抽一次,這個機率等於只考慮子樹權值和的機率),那麼這裏的機率就是\(\frac{w_u}{\sum w}\)。而後每一個根節點顯然能夠獨立考慮,因此只須要把全部根節點的結果直接乘起來就行了。
那麼對於\(w\)也有機率的狀況,設\(f[i][w]\)表示以\(i\)爲根的子樹中,權值和爲\(w\)時根節點合法的機率。
這個隨便轉移一下就很好作了。
如今加上了反向邊,反向邊強制了兒子要在根節點以前出現,而狀態也只要兩種,要麼反向邊在前要麼反向邊在後,那麼設\(f[i][w][j]\)表示以\(i\)爲子樹,子樹和爲\(w\),至少有\(j\)條反向邊不知足條件的機率,既然強制了若干個不反向,那麼就是你枚舉一些邊,而後強制把它變成正向邊,剩下的反向邊直接刪掉,這樣子就能夠求出這個機率。
注意到這個容斥的係數就是簡單的\(\pm 1\),因此只須要直接把容斥係數帶進去算就好了。
這樣子複雜度能夠作到\(O(n^2)\)spa

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 998244353
#define MAX 1010
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int f[MAX][3*MAX],sz[MAX],p[MAX][4],inv[MAX*3],tmp[MAX*3],n,ans;
void dfs(int u,int ff)
{
    sz[u]=1;
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].v;if(v==ff)continue;
        dfs(v,u);
        for(int j=0;j<=3*sz[u];++j)
            for(int k=0;k<=3*sz[v];++k)
            {
                int val=1ll*f[u][j]*f[v][k]%MOD;
                if(i&1)tmp[j+k]=(tmp[j+k]+val)%MOD;
                else tmp[j+k]=(tmp[j+k]+MOD-val)%MOD,tmp[j]=(tmp[j]+val)%MOD;
            }
        sz[u]+=sz[v];for(int j=0;j<=3*sz[u];++j)f[u][j]=tmp[j],tmp[j]=0;
    }
    for(int j=0;j<=sz[u]*3;++j)f[u][j]=1ll*f[u][j]*inv[j]%MOD;
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
    {
        int a1=read(),a2=read(),a3=read();
        int inv=fpow(a1+a2+a3,MOD-2);
        f[i][1]=1ll*a1*inv%MOD;
        f[i][2]=2ll*a2*inv%MOD;
        f[i][3]=3ll*a3*inv%MOD;
    }
    for(int i=1;i<n;++i)
    {
        int u=read(),v=read();
        Add(u,v);Add(v,u);
    }
    inv[0]=inv[1]=1;for(int i=2;i<=3*n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    dfs(1,0);for(int i=0;i<=3*n;++i)ans=(ans+f[1][i])%MOD;
    printf("%d\n",ans);
    return 0;
}
相關文章
相關標籤/搜索