CF1874C Jellyfish and EVA 题解

题意

给定一个有向无环图,对于任意一条边 (ui,vi),有 ui<vi

定义一次从节点 u 开始的移动为如下过程:

  1. Alice 选择从 u 出发的且未被删除的一条边。

  2. Bob 在从 u 出发的且未被删除的边中等概率随机选择一条。

  3. 若两人选择的边相同,则向这条边移动,否则继续选择。

如果不存在从当前节点 u 出发且未被删除的边,那么定义此次移动是失败的。

Alice 采取最优策略,求他们实现移动 1n 的概率。

1n5000)。

题解

定义 fu 代表从节点 u 实现移动 un 的最大化概率,那么可见答案为 f1,由于特殊的边的限制,从 1n 显然是一个合法的拓扑序,逆序遍历转移一定合法,下面考虑如何转移。

d=degreeu,定义从 u 出发的所有边的终点依次为 v1,v2,,vd,将其按 fv 为关键字降序排列得到序列 v

可以发现,若 Alice 选择边的方案钦定,那么可以得出移动到每个终点的概率,设有长度为 d 的序列 p,其中 p1 表示移动到 v1 的概率,那么我们有

fu=i=1dfvipi

那么采取最优操作的实质即为通过改变操作序列来最大化上述和式的值。

由于在任意一次选择中,每个点被 Bob 选择的概率相等,那么显然选择 f 值最大的终点可以获得更大的概率。这样我们就得到了最优操作的策略:选择 f 值最大的终点。

gi 表示在有 i 个点的情况下的最优 p 序列,那么有

g1=[1.0]g1=[0.5,0.0]

对于 i>2 的情况,根据上述策略,我们可以发现 Alice 第一次选择的点一定为 v1,那么我们有

gi,1=1i(i>1)

对于 j>1,那么第一次显然不可能成功移动到 vj。若最终成功移动到了 vj,那么有第一次移动一定失败且 vj 没有被删除。那么此时我们可以从 i2 个节点的状态转移答案。考虑通过枚举除 v1 外被删除的节点来实现转移,设另外一个被删除的节点为 vk,那么有

  • j<k,那么 vj 从当前的第 j 优节点转化为 第 j1 优节点,有转移 gi,jgi2,j1(j<k)

  • k<j,那么 vj 从当前的第 j 优节点转化为 第 j2 优节点,有转移 gi,jgi2,j2(k<j)

发现具体的转移与 k 无关,通过计算 j<k 的概率和 k>j 的概率即可完成转移,有转移式

gi,j={1ij=1j2i×gi2,j2+iji×gi2,j1otherwise.

预处理出 g 数组即可实现转移,复杂度 O(n2),可以通过本题。

Code

#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef long double realType;
typedef std::vector<realType> RealVector;
typedef std::vector<RealVector> RealMatrix;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType T;

    std::cin >> T;

    for (int testcase = 0; testcase < T; ++testcase) {
        valueType N, M;

        std::cin >> N >> M;

        RealMatrix G(N + 1, RealVector(N + 1, 0));

        for (valueType i = 1; i <= N; ++i) {
            G[i][1] = (realType) 1 / i;

            for (valueType j = 2; j <= i && i - 2 > 0; ++j)
                G[i][j] = G[i - 2][j - 2] * (j - 2) / i + G[i - 2][j - 1] * (i - j) / i;
        }

        ValueMatrix Graph(N + 1);

        for (valueType i = 0; i < M; ++i) {
            valueType u, v;

            std::cin >> u >> v;

            Graph[u].push_back(v);
        }

        RealVector F(N + 1, 0);

        F[N] = 1;

        for (valueType i = N - 1; i >= 1; --i) {
            auto const degree = (valueType) Graph[i].size();

            RealVector to;

            to.reserve(degree);

            for (auto const &iter: Graph[i])
                to.push_back(F[iter]);

            std::sort(to.begin(), to.end(), std::greater<>());

            F[i] = 0;

            for (valueType j = 1; j <= degree; ++j)
                F[i] += G[degree][j] * to[j - 1];
        }

        std::cout << std::fixed << std::setprecision(10) << F[1] << std::endl;
    }

    return 0;
}
posted @   User-Unauthorized  阅读(186)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示