【2021牛客寒假第五场】B-比武招亲(上)排列组合

本文介绍了在2021牛客网寒假第五场ACM竞赛中的B题——比武招亲的解题思路,主要围绕最大值和最小值的贡献计算,涉及不递减序列的组合公式C(n+m-1,m)的应用。作者详细解释了如何通过化简得到最终的贡献表达式,并提供了44ms的代码实现。
摘要由CSDN通过智能技术生成

【2021牛客寒假第五场】B-比武招亲(上)排列组合


传送门: https://ac.nowcoder.com/acm/contest/9985/B

题意

在这里插入图片描述

思路

考 虑 最 大 值 和 最 小 值 贡 献 。 考虑最大值和最小值贡献。

先 看 最 大 值 : 先看最大值:
假 设 我 们 选 择 最 大 值 为 x , 则 剩 下 m − 1 个 位 置 只 能 选 不 超 过 x 的 数 字 假设我们选择最大值为x,则剩下m-1个位置只能选不超过x的数字 xm1x
题 目 表 示 排 完 序 之 后 本 质 不 同 ! \red{题目表示排完序之后本质不同!} !
所 以 就 是 在 不 超 过 x 的 数 字 中 任 意 重 复 选 择 m − 1 个 并 且 生 成 不 递 减 序 列 的 个 数 。 所以就是在不超过x的数字中任意重复选择m-1个并且生成不递减序列的个数。 xm1

没 错 , n 个 中 选 m 个 数 ( 可 重 复 ) 且 不 递 减 序 列 个 数 为 C n + m − 1 m 。 请 自 行 百 度 ! 没错,n个中选m个数(可重复)且不递减序列个数为C_{n+m-1}^{m}。请自行百度! nm()Cn+m1m

x = n 时 , 贡 献 为 n ∗ C n + m − 2 m − 1 x=n时,贡献为n*C_{n+m-2}^{m-1} x=nnCn+m2m1
x = n − 1 时 , 贡 献 为 ( n − 1 ) ∗ C n − 1 + m − 2 m − 1 x=n-1时,贡献为(n-1)*C_{n-1+m-2}^{m-1} x=n1(n1)Cn1+m2m1

所 以 我 们 最 大 值 的 贡 献 就 是 所以我们最大值的贡献就是

∑ i = 1 n ( n − i + 1 ) ∗ C n − i + 1 + m − 2 m − 1 \sum_{i=1}^n(n-i+1)*C_{n-i+1+m-2}^{m-1} i=1n(ni+1)Cni+1+m2m1

同 理 , 最 小 值 就 是 m − 1 个 位 置 必 须 选 择 不 小 于 x 的 数 字 , 贡 献 就 是 同理,最小值就是m-1个位置必须选择不小于x的数字,贡献就是 m1x

∑ i = 1 n i ∗ C n − i + 1 + m − 2 m − 1 \sum_{i=1}^ni*C_{n-i+1+m-2}^{m-1} i=1niCni+1+m2m1

这 两 个 式 子 是 我 化 简 过 后 的 。 难 点 就 是 不 递 减 序 列 个 数 是 多 少 。 \red{这两个式子是我化简过后的。难点就是不递减序列个数是多少。}

两 个 减 一 减 得 : 两个减一减得:

∑ i = 1 n ( n − i + 1 ) ∗ C n − i + m − 1 m − 1 \sum_{i=1}^n(n-i+1)*C_{n-i+m-1}^{m-1} i=1n(ni+1)Cni+m1m1

Code(44MS)

#include "bits/stdc++.h"

using namespace std;

typedef long long ll;

const int N = 1e6 + 10;
ll f[N], invF[N], inv[N];
void Init()
{
    f[0] = f[1] = inv[0] = inv[1] = invF[0] = invF[1] = 1;
    for(int i = 2;i < N; i++)
    {
        f[i] = f[i - 1] * i % mod;
        inv[i] = mod - (mod / i) * inv[mod % i] % mod;
        invF[i] = invF[i - 1] * inv[i] % mod;
    }
}

ll C(ll m, ll n)
{
    if(m < 0 || n < 0 || n > m)
        return 0;
    ll ans = f[m];
    ans = ans * invF[n] % mod;
    ans = ans * invF[m - n] % mod;
    return ans;
}

//ll quick_pow(ll a, ll b) {
//    ll ans = 1;
//    while(b) {
//        if(b & 1) ans = ans * a % mod;
//        a = a * a % mod;
//        b >>= 1;
//    }
//    return ans % mod;
//}

void solve() {
    Init();
    ll n, m; cin >> n >> m;
    ll ans = 0;
    // C(n + m - 1, m) n个数中选m个不递减个数
    for(ll i = 1;i <= n; i++) {
        // cout << "个数:" << C(n - i + 1 + m - 1 - 1, m - 1) << endl;
        ans = (ans + (n - 2 * i + 1) * C(n - i + m - 1, m - 1) % mod) % mod;
    }
    cout << (ans % mod + mod) % mod << endl;
}

signed main() {
    solve();
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值