2020CCPC [Weihai Site]-C. Rencontre(樹,貢獻)

2020CCPC [Weihai Site]-C. Rencontre(樹,貢獻)

題面:

題意:

給定一個含有\(\mathit n\)個節點的樹,每一個邊都有其邊權,現在有三個科學家,每一個科學家都有一個節點列表,代表他今晚會從列表中等概率的選擇一個節點住下。每個科學家的選擇相互獨立,都是等概率的。

第二天三個科學家會選擇一個節點使其他們到該點的路徑權值總和最小,現在讓你編程求出科學家們到該點的路徑權值總和的期望值。

思路:

顯然一共有\(m_1*m_2*m_3\)種住宿方案。

直接暴力求解顯然會超時,那麼我們不妨考慮每一個邊對期望值的貢獻。

我們可以推出如下結論:一個邊在某種方案中被走過纔對期望有貢獻,而一個邊在某種方案中最多隻會被一個科學家走,且該邊如果必須被走時當且僅當:刪除該邊生成的兩個子圖中均有科學家住宿。

那麼考慮下計算刪除該邊\(e_i\)生成的兩個子圖中均有科學家住宿的方案數爲左右科學家123可選節點個數組合計算一下。

代碼:

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=2e5+10;
int n;
ll m[3];
vector<pii>g[N];
vector<int>p[N];
ll sz[N][3];
double ans,ret;
void dfs(int u,int fa){
    for(int x:p[u]) sz[u][x]=1;
    for(pii x:g[u]){
        if(x.fi==fa) continue;
        dfs(x.fi,u);
        for(int i=0;i<3;i++) sz[u][i]+=sz[x.fi][i];
        ans+=sz[x.fi][0]*sz[x.fi][1]*(m[2]-sz[x.fi][2])*x.se/ret;
        ans+=sz[x.fi][0]*sz[x.fi][2]*(m[1]-sz[x.fi][1])*x.se/ret;
        ans+=sz[x.fi][1]*sz[x.fi][2]*(m[0]-sz[x.fi][0])*x.se/ret;

        ans+=(m[0]-sz[x.fi][0])*(m[1]-sz[x.fi][1])*sz[x.fi][2]*x.se/ret;
        ans+=(m[0]-sz[x.fi][0])*(m[2]-sz[x.fi][2])*sz[x.fi][1]*x.se/ret;
        ans+=(m[1]-sz[x.fi][1])*(m[2]-sz[x.fi][2])*sz[x.fi][0]*x.se/ret;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2,x,y,w;i<=n;i++){
        scanf("%d%d%d",&x,&y,&w);
        g[x].push_back(pii(y,w));
        g[y].push_back(pii(x,w));
    }
    for(int i=0;i<3;i++){
        scanf("%d",&m[i]);
        for(int j=1,x;j<=m[i];j++){
            scanf("%d",&x);
            p[x].push_back(i);
        }
    }
    ret=(m[0]*m[1]*m[2]);
    dfs(1,0);
    printf("%.6f\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章