这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2024-01-13 16:47阅读: 11评论: 0推荐: 0

[Keyence2019] Paper Cutting

Paper Cutting

Luogu AT_keyence2019_f

题面翻译

有一个 (H+1)×(W+1) 的网格,网格中有 H 条水平线和 W 条竖直线。

你需要执行 K 次操作,每次沿一条水平线或竖直线将网格切开。定义一次操作的权值为切割后网格被切分的块数。

定义一个操作序列的权值为 K 次操作的权值和。

求所有操作序列的权值之和,答案对 109+7 取模。

其中 1H,W1071KH+W,且 H,W,K 为整数。

Solution

考虑单次操作的贡献是什么,假设当前为第 t 次操作。考虑第 t 次操作为当前操作的操作序列个数,容易算出为:

t!(kt)!(H+WtKt)

而这次操作的贡献为:

i=0t(Hi)(Wti)(i+1)(ti+1)

那么贡献即为:

t!(Kt)!(H+WtKt)i=0t(Hi)(Wti)(i+1)(ti+1)

序列个数不难 O(n)O(1) 计算,而贡献为 O(n) 计算,考虑优化。

化式子:

i=0t(Hi)(Wti)(i+1)(ti+1)=(t+1)(i=0t(Hi)(Wti))+i(ti)(i=0t(Hi)(Wti))

前半部分直接使用范德蒙德卷积,后半部分拆一下组合数:

=(t+1)(H+Wt)+i=0tH!W!(i1)!(Hi)!(ti1)!(Wt+1)!=(t+1)(H+Wt)+i=0tHW(H1)!(W1)!(i1)!(Hi)!(ti1)!(Wt+1)!=(t+1)(H+Wt)+HWi=0t(H1i1)(W1ti1)

同样使用范德蒙德卷积可以得到:

=(t+1)(H+Wt)+HW(H+W2t2)

显然可以 O(n)O(1) 计算。

时间复杂度 O(n)

Code
int N, M, K;
mint fac[_N], ifac[_N];
void init(int n) {
    fac[0] = 1; For(i, 1, n) fac[i] = fac[i-1] * i;
    ifac[n] = 1 / fac[n]; Rof(i, n, 1) ifac[i-1] = ifac[i] * i;
}
mint binom(int x, int y) {
    if (x < y || y < 0) return 0;
    return fac[x] * ifac[y] * ifac[x-y];
}
void _() {
    cin >> N >> M >> K; init(N + M);
    mint ans = 0;
    For(k, 1, K) {
        mint tmp = fac[k] * fac[K - k] * binom(N + M - k, K - k);
        tmp *= (k + 1) * binom(N + M, k) + binom(N + M - 2, k - 2) * N * M;
        ans += tmp;
    }
    cout << ans << '\n';
}
posted @   Hanx16Msgr  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起