"蔚来杯"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;
}