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

ARC114E - Paper Cutting 2

Solution

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

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

Part one

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

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

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

Part two

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

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

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

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

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

  • x < w 1 x < w_1 x<w1,则前面不能出现在 [ x , w 1 ) ∪ [ w 1 , w 2 ) [x,w_1)\cup[w_1,w_2) [x,w1)[w1,w2)中的数。
  • w 1 ≤ x < w 2 w_1 \leq x < w_2 w1x<w2,则前面不能出现 [ w 1 , w 2 ) [w_1,w_2) [w1,w2)中的数。
  • x > w 2 x > w_2 x>w2,则前面不能出现在 ( w 2 , x ] ∪ [ w 1 , w 2 ) (w_2,x]\cup[w_1,w_2) (w2,x][w1,w2)中的数。

对于第一种情况,我们枚举 x x x,再枚举它在排列中的位置,贡献即为:
∑ i = 1 w 1 − 1 ∑ j = 1 W + H − 2 ( W + H − 2 − ( ( w 2 − 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 = 1 W + H − 2 ( W + H − 2 − w 2 + w 1 j ) − ( W + H − 2 − w 2 + 1 j ) \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、付费专栏及课程。

余额充值