20211106 游戏 game

Description

给定两个人的血量 \(n\)\(m\) 和攻击到对方的概率 \(p\)\(q\) ,每次攻击到的话血量 \(-1\) ,回合制,问先手获胜的概率,对 998244353 取模。

多测。

\(\sum (n + m)\leq 5 \cdot 10 ^ 6 ,\ t \leq 10 ^ 4\)

Analysis

这好像看起来是一个比较良心的题??

实际上感觉还是很难操作的吧。。主要是我们并不清楚到底什么时候要结束。

容易发现对于每一个回合,只有四种情况。其中最影响我们的就是如果两个人都没有打到对方,因为这种情况我们不知道有多少个。

实际上的话本质上这玩意不影响我们的答案,因为四种情况都不相互影响,再加上对血量又没有影响,所以我们可以干脆不看这种情况。

Solution

接着 Analysis 的想法,然后我们设只打中先手的概率为 \(P_a\) ,只打中后手的概率为 \(P_b\) ,同时击中的概率为 \(P_c\)

要注意一下最后一个回合先手打死后手了,后手就没机会了,所以的话最后一次我们单独计算。剩下的就相当于我们就知道了 B 情况和 C 情况的总数,就是 \(m - 1\)

这样的话我们就可以枚举 C 情况的个数,那么很显然打中先手的数量要保证小于 \(n\) ,大概确定了多少个 A ,多少个 B ,多少个 C ,式子就是:

\[\sum_{i = 0}^{\min(n - 1, m - 1)} P_b^i \cdot P_c^{m - 1 - i} \cdot \sum_{j = 0}^{n - 1 - i} P_a^{j} \]

同时的话因为顺序不同就是另一种情况,而且每种情况内部又是无差别的,所以我们就再加上填法的系数,大概就是:

\[\sum_{i = 0}^{\min(n - 1, m - 1)} C_{m - 1}^{i} \cdot P_b^i \cdot P_c^{m - 1 - i} \cdot \sum_{j = 0}^{n - 1 - i} C_{m - 1 + i}^{i} \cdot P_a^{j} \]

这玩意是 \(O(n ^ 2\log n)\) 的,显然不能过题,不过发现复杂度瓶颈就是后面那坨关于 \(P_a\) 的东西,这玩意可以预处理前缀和,包括前面的 \(i\) 次方也可以预处理,可以顺便把快速幂的 \(\log\) 去掉,那这下就是严格 \(O(n)\) 的了,可以通过此题。

Code

/*
3
1 1 50 50
100000 1 99 100
11 45 14 19
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 10;
const ll mod = 998244353;
ll n, m, p, _p, q, _q, ret;
ll pa[N], pb[N], pc[N], sum[N];
ll fac[N], inv[N], inv10, ans;
inline ll read() {
	ll s = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {s = (s << 3) + (s << 1) + ch - '0'; ch = getchar();}
	return s * w;
}
inline ll ksm(ll a, ll b) {
	ll tmp = 1;
	while (b) {
		if (b & 1) tmp = tmp * a % mod;
		a = a * a % mod; b >>= 1;
	}
	return tmp;
}
inline ll C(int n, int m) {
	if (n < m) return 0;
	return (fac[n] * inv[m] % mod) * inv[n - m] % mod;
}
inline void mian() {
	n = read(); m = read();
	p = read(); _p = 100 - p;
	q = read(); _q = 100 - q;
	(p *= inv10) %= mod; (_p *= inv10) %= mod;
	(q *= inv10) %= mod; (_q *= inv10) %= mod;
	ll hv = ksm((1 - (_p * _q % mod) + mod), mod - 2);
	pb[1] = (_q * p % mod) * hv % mod;
	pa[1] = (_p * q % mod) * hv % mod;
	sum[1] = (sum[0] + C(m, 1) * pa[1] % mod) % mod;
	pc[1] = (q * p % mod) * hv % mod;
	ans = hv * p % mod; ret = 0;
	for (int i = 2; i <= max(n, m); ++i) {
		pa[i] = pa[i - 1] * pa[1] % mod;
		pb[i] = pb[i - 1] * pb[1] % mod;
		pc[i] = pc[i - 1] * pc[1] % mod;
		sum[i] = (sum[i - 1] + C(m + i - 1, i) * pa[i] % mod) % mod;
	}
	for (int i = 0; i < min(n, m); ++i) {
		ll res = pc[i] * pb[m - 1 - i] % mod;
		(ret += (res * C(m - 1, i) % mod) * sum[n - i - 1] % mod) %= mod;
	}
	printf("%lld\n", (ans + mod) * ret % mod);
}
int main() {
//	freopen("game.in", "r", stdin);
//	freopen("game.out", "w", stdout);
	pa[0] = pb[0] = pc[0] = sum[0] = 1;
	fac[0] = inv[0] = 1;
	for (ll i = 1; i < N; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	inv[N - 1] = ksm(fac[N - 1], mod - 2);
	for (ll i = N - 2; i; --i) {
		inv[i] = inv[i + 1] * (i + 1) % mod;
	}
	inv10 = ksm(100, mod - 2);
	int t = read();
	while (t--) mian();
	return 0;
}
posted @ 2021-11-07 19:48  Illusory_dimes  阅读(42)  评论(2编辑  收藏  举报