“蔚来杯“2022牛客暑期多校训练营10

"蔚来杯"2022牛客暑期多校训练营10

[题目链接]("蔚来杯"2022牛客暑期多校训练营10_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com))

H Wheel of Fortune

题目大意

两个人在打炉石。双方英雄血量分别为A和B,并且双方各有7个随从,血量为ai和bi

有一个操作,每次从场上的人中随机选择一个血量>0的人攻击,该人血量减10。A和B谁的血量先<=0,谁输。

问A赢的概率。

题解

通过观察可得,对于随从的攻击不影响最终获胜的概率,因为对任何随从的攻击相当于白费一次机会,A和B的血量不会变化。

令a = ⌈ A / 10 ⌉ , b = ⌈ B / 10 ⌉,若当A取得胜利时,

① 攻击数为b,P0=1 / 2b;(b次都是攻击B的,每次攻击B的概率为1 / 2,一共b次)

② 攻击数为b+1,P1=(Cbb-1 / 2b) * 1 / 2;(在前b次,有b-1次攻击了B,且在第b+1次,攻击了B)

依此类推,最后一次A可以取得胜利的攻击次数是b+a-1,概率为(Cb+a-2b-1 / 2b+a-2) * 1 / 2。

所以A总的获胜概率为上述概率的和。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e7 + 5;
const int mod = 998244353;
ll A, B, a, b, x, res;
ll fact[maxn];
ll qpow(ll a, ll n, ll mod)
{
    ll res = 1;
    while (n)
    {
        if (n & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return res;
}
ll inv(ll a, ll p)
{
    return qpow(a, p - 2, p);
}
ll C(ll b, ll a)
{
    return fact[a] * inv(fact[b], mod) % mod * inv(fact[a - b], mod) % mod;
}
void init()
{
    fact[0] = 1;
    for (int i = 1; i < maxn; i++)
    {
        fact[i] = fact[i - 1] * i % mod;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    init();
    cin >> A;
    for (int i = 1; i <= 7; i++)
        cin >> x;
    cin >> B;
    for (int i = 1; i <= 7; i++)
        cin >> x;
    a = ceil(1.0 * A / 10), b = ceil(1.0 * B / 10);
    for (int i = b; i <= b + a - 1; i++)
        res = (res + C(b - 1, i - 1) * inv(qpow(2, i, mod), mod) % mod) % mod;
    cout << res << endl;
    return 0;
}

F Shannon Switching Game?

题目大意

给定一个无向图,初始时有一个物品在s点,两个玩家Join Player和Cut Player轮流行动,Cut Player先手。

Cut Player每次可以删除一条和物品所在位置相邻的边;Join Player每次可以将物品沿着一条未删除的边移动,并且删除这条边。

如果物品在某刻被移动到t,则Join Player获胜,否则Cut Player获胜,求双方最优策略下的胜者。

题解

定义一个点集,该点集中的点在双方最优策略下可以到达t点。

初始时点集只有t点。

某一个点可以添加到点集的条件:该点与点集中的所有点之间的边的数量大于等于2即可。因为Cut Player只能删除一条边,然后Join Player可以从该点与点集的其他边到达点集。

最后判断s是否在该点集中即可。

代码

#include <bits/stdc++.h>
using namespace std;
int T, n, m, s, t;
const int maxn = 1e2 + 5;
int g[maxn][maxn], num[maxn];
bool vis[maxn];
bool bfs()
{
    queue<int> q;
    q.push(t);
    vis[t] = 1;
    while (q.size())
    {
        int u = q.front();
        q.pop();
        for (int i = 1; i <= n; i++)
        {
            if (vis[i])
                continue;
            num[i] += g[u][i];
            if (num[i] > 1)
            {
                q.push(i);
                vis[i] = 1;
            }
        }
    }
    return num[s] > 1;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> T;
    while (T--)
    {
        memset(vis, 0, sizeof vis);
        memset(g, 0, sizeof g);
        memset(num, 0, sizeof num);
        cin >> n >> m >> s >> t;
        while (m--)
        {
            int u, v;
            cin >> u >> v;
            g[u][v]++;
            g[v][u]++;
        }
        cout << (bfs() ? "Join Player" : "Cut Player") << endl;
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值