题解:CF1874C Jellyfish and EVA

题目简述

有向无环图,边从小编号指向大编号。从 1 出发要到 n。每步在 u 时,水母选一条出边(最优),明日香随机等概率选一条出边。若两边指向相同顶点,则到达该点;否则留在 u 且这两条边被摧毁。若 \(u \neq n\) 且无出边则失败。求成功最大概率。

n 总和 ≤5000,m 总和 ≤2e5。

模拟赛又输了。。。

分析

假设当前在节点 \(u\),\(v \in son_u\) 最优策略显然是尽可能先去那些更可能到达中点的 \(v\),自然的设计 \(f_u\),表示从 \(u\) 到 \(n\) 的最大成功概率,因为这样在计算 \(f_u\) 的时候已经知道 \(f_v\) 了。

考虑怎么求转移系数,设 \(g_{i,j}\) 表示一个后继儿子个数为 \(i\) 的点,去第 \(j\) 优的儿子的概率,显然可以预处理。

#include<bits/stdc++.h>
#define int long long
#define rep(i, l, r) for(int i = (l); i <= (r); ++ i)
#define per(i, r, l) for(int i = (r); i >= (l); -- i)
#define fi first
#define se second
#define endl '\n'
#define pii pair<int, int>
#define ull unsigned long long
#define pb push_back

using namespace std;
const int N = 5000 + 10;

int d[N];
double f[N], h[N], g[N][N];
vector<int> p[N], son[N];
void Jail() {
    int n, m;
    cin >> n >> m;
    rep(i, 1, m) {
        int u, v;
        cin >> u >> v;
        p[v].pb(u);
        son[u].pb(v);
        d[u] ++;
    }
    rep(i, 1, n) {
        g[i][1] = 1.0 / i;
        rep(j, 2, i) {
            g[i][j] = g[i - 2][j - 2] * (j - 2) / i + g[i - 2][j - 1] * (i - j) / i;
        }
    }
    f[n] = 1;
    queue<int> q; 
    rep(i, 1, n) if(d[i] == 0) q.push(i);
    while(! q.empty()) {
        int u = q.front();
        q.pop();
        int cnt = 0;
        for(auto v : son[u]) {
            h[++ cnt] = f[v];
        }
        sort(h + 1, h + cnt + 1, greater<double>());
        rep(i, 1, cnt) {
            f[u] += h[i] * g[cnt][i];
        }
        for(auto t : p[u]) {
            d[t] --;
            if(d[t] == 0) q.push(t);
        }
    }
    cout << fixed << setprecision(12) << f[1] << '\n';
    rep(i, 1, n) {
        son[i].clear();
        p[i].clear();
        f[i] = 0;
        d[i] = 0;
    }
}
signed main() {    
    // freopen("drive.in", "r", stdin);
    // freopen("drive.out", "w", stdout);    
    // freopen("a.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    ios :: sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int T = 1;
    cin >> T;
    while(T --) Jail();
    return 0;
}
posted @ 2026-08-15 16:47  Koswel  阅读(5)  评论(0)    收藏  举报