[CF1392H] ZS Shuffles Cards

[题目链接]

https://codeforces.com/contest/1392/problem/H

[题解]

首先注意到抽到两次 "鬼牌" 的相邻时间间隔始终是固定的。

不妨将每次抽到一张鬼牌并重排牌序之前的抽卡流程为一次 "迭代"。 考虑一次 "迭代" 的期望轮数。

有 \(E(x) = \frac{n}{n + m} + 2 \cdot \frac{n}{n + m} \cdot \frac{m}{n + m - 1} + 3 \cdot \frac{n}{n + m} \cdot \frac{n - 1}{n + m - 1} \cdot \frac{m}{n + m - 2} + ... + = \sum_{i}{i * \frac{m}{n + m + 1 - i} \prod_{j}{\frac{n - j}{n + m - j}}}\)。

令 \(w_{k} = \prod_{j=0}^{k - 2}{\frac{n - j}{n + m - j}}\) , 可以通过递推的方式在 \(O(NlogN)\) 时间内求解 \(E(x)\)。

接着考虑期望需要多少轮迭代才能抽到所有的牌。

不妨设 \(f_{k}\) 表示还有 \(k\) 张不在牌堆里的牌期望轮数。

那么有 \(\frac{m}{m + k}\) 的概率抽到 \(Joker\) , 从而结束一轮迭代。

另有 \(\frac{k}{m + k}\) 的概率抽到一张需要的牌 , 转化为 \((k - 1)\) 的子问题。

也就是说 \(f_{k} = \frac{m}{m + k}(f_{k} + 1) + \frac{k}{m + k}f_{k - 1}\)。

解得 \(f_{k} = f_{k - 1} + \frac{m}{k}\)。

也就是说 \(f_{n} = f_{1} + \sum_{i = 2}^{n}{\frac{m}{i}}\)。

\(f_{1}\) 显然为 \(\frac{1}{\frac{1}{m + 1}} = m + 1\) , 于是 \(f_{n} = 1 + m\sum_{i = 1}^{n}{\frac{1}{i}}\)。

至此我们成功地在线性时间内求解了 \(f\)。

答案显然为 \(E(x)f(n)\)。 这样就可以做到 \(O(NlogN)\) 的优秀复杂度了。

但事实上 \(E(x)\) 可以不通过递推得到 , 考虑期望的线性性 , 在一轮迭代中 , 每张数字牌都有 \(\frac{1}{m + 1}\) 的概率被抽出 , 概率相加就是期望(还要加上 \(1\) , 表示最终摸到一张 \(Joker\))。

故 \(E(x) = \frac{n}{m + 1} + 1\)。

这样做时间复杂度为 \(O(N)\) (瓶颈在于线性求逆元)。

[代码]

#include<bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
 
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
 
const int mod = 998244353;
 
int N , M;
 
inline void inc(int &x , int y) {
	x = x + y < mod ? x + y : x + y - mod;
}
inline int qPow(int a , int b) {
	int c = 1;
	for (; b; b >>= 1 , a = 1LL * a * a % mod) if (b & 1) c = 1LL * c * a % mod;
	return c;
}
 
int main() {
	
	 scanf("%d%d" , &N , &M); 
	 int ans = 1LL * (N + M + 1) * qPow(M + 1 , mod - 2) % mod;
	 int ex = 0;
	 for (int i = 1; i <= N; ++i) inc(ex , qPow(i , mod - 2));
	 ex = (1ll * ex * M % mod + 1) % mod;
	 printf("%d\n" , 1ll * ans * ex % mod);
     return 0;
}
上一篇:LeetCode228场周赛解题报告


下一篇:COJ16G