CodeForces1312D 组合数

题意

找出满足下列条件的数组个数:

  • 包含 n 个元素
  • 每个元素的数值范围在 1 到 m 之间
  • 数组中恰好只有一对元素的数值相等
  • 数组中存在一个下标 i 满足在 i 之前数组是严格递增的,而在 i 之后数组是严格递减的 (若 j < i 则 aj < aj + 1,若 j ≥ i 则 aj > aj + 1)。

题解

显然是一个组合数的题,首先考虑从m个数字中取出n - 1个不同的数字 C(m,n - 1),然后从这个n - 1个数字中选取一个作为重复元素(不能是当中的最大值),有n - 2中情况,剩下的非顶点以及非重复元素的数字分为在左侧和在右侧两种可能,即2 ^ (n - 3)
因此推出来的公式就是C(n - 1, m) * (n - 2) * (2 ^ (n - 3)), 对于n == 2的场景,特判为0即可

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define fi first
#define se second
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define mp make_pair
const int maxn = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
int N,M,K;
int F[maxn],Finv[maxn],inv[maxn];
void init() {
    inv[1] = 1;
    for(int i = 2; i < maxn ; i ++) {
        inv[i] = (mod - mod / i) * 1ll * inv[mod % i] % mod;
    }
    F[0] = Finv[0] = 1;
    for(int i = 1; i < maxn; i ++) {
        F[i] = F[i - 1] * 1ll * i % mod;
        Finv[i] = Finv[i - 1] * 1ll * inv[i] % mod;
    }
}
LL C(int n,int m) { // C(n,m)
    if(m < 0 || m > n) return 0;
    return F[n] * 1ll * Finv[n - m] % mod * Finv[m] % mod;
}
LL q_p(LL a,LL b) {
    LL ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
int main(){
    LL n,m; init();
    scanf("%lld%lld",&n,&m);
    if(n == 2) {
        cout << 0 << endl;
        return 0;
    }
    LL ans = C(m,n - 1) *  (n - 2) % mod * q_p(2,n - 3) % mod;
    cout << ans << endl;
    return 0;
}


posted @ 2020-10-02 20:06  Hugh_Locke  阅读(113)  评论(0编辑  收藏  举报