ARC114E - Paper Cutting 2(组合数学,概率与期望)

本文提供了一种求解ARC114E-PaperCutting2问题的有效算法,通过将问题转化为排列问题,利用组合数学技巧计算合法操作序列的期望长度。文章详细介绍了分步求解策略,并提供了复杂度为O(W+H)的解决方案。

ARC114E - Paper Cutting 2

Solution

考场上时间不够,没刚出来QAQ。

做法和官解本质相同,只是官解运用期望的线性性直接导出答案,而这里是对于所有方案统计贡献在除以方案数,从期望的定义上计算答案。可能稍显复杂。

Part one

我们要求的是合法操作序列的期望长度。

问题大概可以用一个类似《PKUWC2018猎人杀》的经典的套路转化为:
设有一个W+H−2W+H-2W+H2条线组成的排列p1p2...pnp_1p_2...p_np1p2...pn,其中pip_ipi的贡献为111当且仅当不存在一个pj(j<i)p_j(j<i)pj(j<i)可以把pip_ipi叉掉,也就是说pip_ipi前面没有一个能结束游戏或者把pip_ipi的那一半白纸去掉的数,否则pip_ipi贡献为000,一个排列的贡献是所有数的贡献和。

不难看出每个排列都映射到一组合法操作序列(即贡献为111pip_ipi序列),每个排列的贡献对应一组合法方案的长度,根据期望的定义(∑cipi\sum c_ip_icipi)容易证明上面所有排列的期望贡献和就是我们要求的合法方案的长度和。

Part two

因此我们想要求所有W+H−2W+H-2W+H2条线的(W+H−2)!(W+H-2)!(W+H2)!种排列的期望贡献,我们可以求出所有排列的贡献再除以方案数。

于是问题变成怎么求(W+H−2)!(W+H-2)!(W+H2)!种排列的贡献和。

这里我们运用类似这场ARCARCARCCCC题的方法,对于每个数,统计其对答案的贡献。也就是考虑这个数xxx会在多少个排列里贡献为111,即有多少个排列满足在xxx之前不存在能叉掉xxx的数。

设行的编号为1,2,...,H−11,2,...,H-11,2,...,H1列的编号为1,2,...,W−11,2,...,W-11,2,...,W1,不妨令w1<w2,h1<h2w_1<w_2,h_1<h_2w1<w2,h1<h2(显然这个顺序没有影响)。

先考虑列的贡献,分类讨论:

  • x<w1x < w_1x<w1,则前面不能出现在[x,w1)∪[w1,w2)[x,w_1)\cup[w_1,w_2)[x,w1)[w1,w2)中的数。
  • w1≤x<w2w_1 \leq x < w_2w1x<w2,则前面不能出现[w1,w2)[w_1,w_2)[w1,w2)中的数。
  • x>w2x > w_2x>w2,则前面不能出现在(w2,x]∪[w1,w2)(w_2,x]\cup[w_1,w_2)(w2,x][w1,w2)中的数。

对于第一种情况,我们枚举xxx,再枚举它在排列中的位置,贡献即为:
∑i=1w1−1∑j=1W+H−2(W+H−2−((w2−1)−i+1)j−1) \sum_{i = 1}^{w_1-1}\sum_{j = 1} ^{W + H - 2}\binom{W+H-2-((w_2-1)-i+1)}{j - 1} i=1w11j=1W+H2(j1W+H2((w21)i+1))
用上指标求和化简得:
∑j=1W+H−2(W+H−2−w2+w1j)−(W+H−2−w2+1j) \sum_{j = 1} ^{W + H - 2}\binom{W+H-2-w_2+w_1}{j}-\binom{W+H-2-w_2+1}{j} j=1W+H2(jW+H2w2+w1)(jW+H2w2+1)
这样就可以O(W+H)O(W+H)O(W+H)计算了。

第二种和第三种是类似的,行的贡献也是类似的,这里就不再赘述了。

总时间复杂度O(W+H)O(W+H)O(W+H)

Code

实现上有一点点小细节。

//省略快读和头文件
int fac[MAXN], inv[MAXN];
inline int upd(int x, int y) { return x + y >= mods ? x + y - mods : x + y; }
inline int quick_pow(int x, int y) {
	int ret = 1;
	for (; y ; y >>= 1) {
		if (y & 1) ret = 1ll * ret * x % mods;
		x = 1ll * x * x % mods;
	}
	return ret;
}
inline int C(int x, int y) { return (x < y || y < 0) ? 0 : 1ll * fac[x] * inv[y] % mods * inv[x - y] % mods; }
void Init(int n) {
	fac[0] = 1;
	for (int i = 1; i <= n ; ++ i) fac[i] = 1ll * fac[i - 1] * i % mods;
	inv[n] = quick_pow(fac[n], mods - 2);
	for (int i = n - 1; i >= 0 ; -- i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mods;
}
int solve(int n, int h1, int h2, int w1, int w2, int W) {
	int ans = 0;
	if (w1 > 1)
	for (int i = 2; i <= n - h2 + h1 - w2 + w1 ; ++ i)
		ans = upd(ans, 1ll * fac[n - i] * fac[i - 1] % mods * upd(C(n - h2 + h1 - w2 + w1, i), mods - C(n - h2 + h1 - w2 + 1, i)) % mods);

	if (w1 < w2)
	for (int i = 2; i <= n - h2 + h1 - w2 + w1 + 1; ++ i)
		ans = upd(ans, 1ll * fac[n - i] * fac[i - 1] % mods * C(n - h2 + h1 - w2 + w1, i - 1) % mods * (w2 - w1) % mods);

	if (w2 < W)
	for (int i = 2; i <= n - h2 + h1 - w2 + w1 ; ++ i)
		ans = upd(ans, 1ll * fac[n - i] * fac[i - 1] % mods * upd(C(n - h2 + h1 - w2 + w1, i), mods - C(n - h2 + h1 - W + w1, i)) % mods);
	return upd(ans, 1ll * (W - 1) * fac[n - 1] % mods);
}
signed main() {
#ifndef ONLINE_JUDGE
	freopen("a.in", "r", stdin);
#endif
	int H, W, h1, w1, h2, w2, n; 
	read(H), read(W), read(h1), read(w1), read(h2), read(w2), n = H + W - 2;
	if (w1 > w2) swap(w1, w2);
	if (h1 > h2) swap(h1, h2);
	Init(n);
	printf("%lld\n", 1ll * inv[n] * upd(solve(n, h1, h2, w1, w2, W), solve(n, w1, w2, h1, h2, H)) % mods);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值