ARC114E - Paper Cutting 2
Solution
考场上时间不够,没刚出来QAQ。
做法和官解本质相同,只是官解运用期望的线性性直接导出答案,而这里是对于所有方案统计贡献在除以方案数,从期望的定义上计算答案。可能稍显复杂。
Part one
我们要求的是合法操作序列的期望长度。
问题大概可以用一个类似《PKUWC2018猎人杀》的经典的套路转化为:
设有一个W+H−2W+H-2W+H−2条线组成的排列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,一个排列的贡献是所有数的贡献和。
不难看出每个排列都映射到一组合法操作序列(即贡献为111的pip_ipi序列),每个排列的贡献对应一组合法方案的长度,根据期望的定义(∑cipi\sum c_ip_i∑cipi)容易证明上面所有排列的期望贡献和就是我们要求的合法方案的长度和。
Part two
因此我们想要求所有W+H−2W+H-2W+H−2条线的(W+H−2)!(W+H-2)!(W+H−2)!种排列的期望贡献,我们可以求出所有排列的贡献再除以方案数。
于是问题变成怎么求(W+H−2)!(W+H-2)!(W+H−2)!种排列的贡献和。
这里我们运用类似这场ARCARCARC的CCC题的方法,对于每个数,统计其对答案的贡献。也就是考虑这个数xxx会在多少个排列里贡献为111,即有多少个排列满足在xxx之前不存在能叉掉xxx的数。
设行的编号为1,2,...,H−11,2,...,H-11,2,...,H−1列的编号为1,2,...,W−11,2,...,W-11,2,...,W−1,不妨令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_2w1≤x<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=1∑w1−1j=1∑W+H−2(j−1W+H−2−((w2−1)−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=1∑W+H−2(jW+H−2−w2+w1)−(jW+H−2−w2+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_JUDGEfreopen("a.in", "r", stdin);
#endifint 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;
}