• [2020CCPC威海C] Rencontre


    Description

    给定一棵树,有三个人,每个人有一个点集,表示这个人会等概率随机出现在这些点上。对于每一种确定的情况,三人会选择一个点使得到他们的总距离和最小。求距离和的期望。

    Solution

    首先由结论:距离和为 (frac 1 2 d(a,b) + d(a,c) + d(b,c))

    根据期望的性质,我们可以将每个部分拆出来分别统计。下面考虑如何统计 (d(a,b))

    我们可以分别统计每条边的贡献,这样只需要一个基础的树形 dp 就可以了。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    vector<pair<int, int>> g[N];
    
    int n;
    
    struct Tree
    {
        int val[2][N], sum[2][N], vis[N], ans;
    
        Tree()
        {
            memset(val, 0, sizeof val);
            memset(sum, 0, sizeof sum);
            memset(vis, 0, sizeof vis);
            ans = 0;
        }
    
        void tag(int pos, int col)
        {
            val[col][pos]++;
        }
    
        void dfs(int p)
        {
            vis[p] = 1;
            for (int k = 0; k < 2; k++)
                sum[k][p] = val[k][p];
            for (auto pr : g[p])
            {
                int q = pr.first, w = pr.second;
                if (!vis[q])
                {
                    dfs(q);
                    for (int k = 0; k < 2; k++)
                    {
                        sum[k][p] += sum[k][q];
                        ans += sum[k][q] * (sum[k ^ 1][0] - sum[k ^ 1][q]) * w;
                    }
                }
            }
        }
    
        int solve()
        {
            for (int i = 1; i <= n; i++)
            {
                for (int k = 0; k < 2; k++)
                    sum[k][0] += val[k][i];
            }
            dfs(1);
            return ans;
        }
    } ab, ac, bc;
    
    int na, nb, nc, a[N], b[N], c[N], t1, t2, t3;
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin >> n;
        for (int i = 1; i < n; i++)
        {
            cin >> t1 >> t2 >> t3;
            g[t1].push_back({t2, t3});
            g[t2].push_back({t1, t3});
        }
    
        cin >> na;
        for (int i = 1; i <= na; i++)
            cin >> a[i], ab.tag(a[i], 0), ac.tag(a[i], 0);
    
        cin >> nb;
        for (int i = 1; i <= nb; i++)
            cin >> b[i], ab.tag(b[i], 1), bc.tag(b[i], 0);
    
        cin >> nc;
        for (int i = 1; i <= nc; i++)
            cin >> c[i], ac.tag(c[i], 1), bc.tag(c[i], 1);
    
        int sumDisAB = ab.solve();
        int sumDisAC = ac.solve();
        int sumDisBC = bc.solve();
    
        double ans = 0;
        ans += sumDisAB * 1.0 / na / nb;
        ans += sumDisAC * 1.0 / na / nc;
        ans += sumDisBC * 1.0 / nb / nc;
        ans /= 2;
    
        printf("%.10lf
    ",ans);
    
        return 0;
    }
    
  • 相关阅读:
    JAVA环境安装配置
    使用apache设置绑定多个域名或网站
    C#资源释放及Dispose、Close和析构方法
    【数据库】百万级数据库SQL优化大总结
    【ABP】Abp的AspNetZero5.0版本无法使用ctrl+f5调式
    【.Net】vs2017 自带发布工具 ClickOnce发布包遇到的问题
    【Python】python 反射机制在实际的应用场景讲解
    【.Net】从字符串数组中寻找数字的元素
    【.Net】输出的字符靠右对齐
    【.Net+数据库】sqlserver的四种分页方式
  • 原文地址:https://www.cnblogs.com/mollnn/p/13907399.html
Copyright © 2020-2023  润新知