其他分享
首页 > 其他分享> > CSUSTOJ 写完就捧杯(概率DP + LCA)

CSUSTOJ 写完就捧杯(概率DP + LCA)

作者:互联网

题目链接
题意:
有一个空序列 \(a\) 和一棵 \(n\) 个节点的树,所有节点颜色均为白色,一开始等概率的选择任意一个节点将其染黑,并将这个节点的编号加入到序列 \(a\) 的末尾,接下来的每次操作,都只能等概率的选择与黑色点相邻的白色点,然后将其染黑,并将其编号加入到序列 \(a\) 的末尾。
当选择完\(n\)个点后,求序列\(a\)满足\(i<j\)​​且\(a_i>a_j​\)的\((i,j)​\)​的数量的数学期望是多少。

思路:
概率DP+LCA
一般正向求概率,反向求期望

code:

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <deque>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#include <unordered_map>

#define fi first
#define se second
#define pb push_back
// #define endl "\n"
#define debug(x) cout << #x << ":" << x << endl;
#define bug cout << "********" << endl;
#define all(x) x.begin(), x.end()
#define lowbit(x) x & -x
#define fin(x) freopen(x, "r", stdin)
#define fout(x) freopen(x, "w", stdout)
#define ull unsigned long long
#define ll long long 

const double eps = 1e-5;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1.0);
const int mod = 1e9 + 7;
const int maxn = 2e2 + 10;

using namespace std;

vector<int> v[maxn];
int d[maxn], dp[maxn][12], n;
ll ans, p[maxn][maxn], inv2, invn;

ll qpow(ll a, ll b){
    ll ret = 1;
    while(b){
        if(b & 1)ret = ret * a % mod;
        b >>= 1;
        a = a * a % mod;
    }
    return ret;
}

void dfs(int u, int fa){
    d[u] = d[fa] + 1;
    dp[u][0] = fa;
    for(int i = 1; (1 << i) < d[u]; i ++)dp[u][i] = dp[dp[u][i - 1]][i - 1];

    for(int to : v[u]){
        if(to == fa)continue;
        dfs(to, u);
    }
}

int LCA(int a, int b){
    if(d[a] > d[b])swap(a, b);
    int h = d[b] - d[a];
    for(int i = 10; i >= 0; i --){
        if(h & (1 << i))b = dp[b][i];
    }
    if(a == b)return a;

    for(int i = 10; i >= 0; i --){
        if(dp[a][i] != dp[b][i])a = dp[a][i], b = dp[b][i];
    }
    return dp[a][0];
}   

void root(int u){
    memset(d, 0, sizeof d), memset(dp, 0, sizeof dp);
    dfs(u, 0);
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j < i; j ++){
            int lca = LCA(i, j);
            if(lca == i)ans = (ans + invn) % mod;
            else if(lca == j)continue;
            else{
                int d1 = d[i] - d[lca], d2 = d[j] - d[lca];
                ans = (ans + p[d1][d2] * invn % mod) % mod;
            }
        }
    }
}

int main(){
    scanf("%d", &n);
    inv2 = qpow(2, mod - 2), invn = qpow(n, mod - 2);
    for(int i = 0; i <= n; i ++)p[0][i] = 1;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= n; j ++){
            p[i][j] = (p[i - 1][j] + p[i][j - 1]) % mod * inv2 % mod;
        }
    }

    for(int i = 1; i < n; i ++){
        int a, b;
        scanf("%d%d", &a, &b);
        v[a].pb(b), v[b].pb(a);
    }

    for(int i = 1; i <= n; i ++)root(i);
    printf("%lld\n", ans);
    return 0;
}

标签:CSUSTOJ,int,ll,maxn,DP,捧杯,include,dp,define
来源: https://www.cnblogs.com/lniiwuw/p/15428412.html