codeforces 1312 D (组合数学)

题意

  有 1 ~ m 个数,组成一个含有 n n n个元素的列表,其中 n − 1 n-1 n1个数必须互不相同,剩下一个数出现两次,最大的数必须在列表中间,在它前面的部分严格升序排列,在它后面的部分严格降序排列,求一共有多少个不同的满足要求的列表

思路

  将几个条件分开来考虑

  • 在 m 个数中选择 n − 1 n-1 n1个数,一共有 C m   n − 1 C_m^{\,n-1} Cmn1 种情况
  • 相同的数可以和 n − 1 n-1 n1 个数中除了最大值的任意一个数相同,因为如果最大值重复两遍,两个最大值都必须在中间,无法满足严格升序降序排列,其他值重复可以分别放在最大值两边,故一共有 n − 2 n-2 n2 种情况
  • 当 n 个数选好后,最大值的位置无法选择,重复数则在最大值左右两边各有一个,剩下 n − 3 n - 3 n3 个数可以任意选择在最大值左边或者右边,故有 2 n − 3 2^{n-3} 2n3

  最后答案即为所有情况的成绩 a n s = C m   n − 1 × ( n − 2 ) × 2 n − 3 ans=C^{\,n-1}_m \times (n-2) \times 2^{n-3} ans=Cmn1×(n2)×2n3

  求组和数时,因为模数是质数,直接利用公式暴力求解,用乘法逆元处理除法求模

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL n,m;
const LL mod = 998244353;
LL qpow(LL a,LL b)
{
    LL res = 1;
    while(b>0)
    {
        if(b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
LL comb(LL n,LL m)
{
    LL res = 1;
    LL tmp = 1;
    for(int i = 1; i <= n; i++) res = res * i % mod;
    for(int i = 1; i <= m; i++) tmp = tmp * i % mod;
    for(int i = 1; i <= n-m; i++) tmp = tmp * i % mod;
    return res * qpow(tmp, mod-2) % mod;
}
int main()
{
    cin.sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    LL ans = comb(m, n-1) * (n-2) % mod * qpow(2,n-3) % mod;
    cout << ans << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值