Codeforces 1312D Count the Arrays

题目链接

组合学得好, 玄学少不了, 本题的关键点在于除了一个数可以出现2次, 每个数都只能出现一次, 那就是说选定了数字就选定了顺序, 我们只需找到如何选择数字即可
因为有一个重复, 那就从\(m\)中选择\(n-1\)个, 即\(C^{n-1}_{m}\), \(n-1\)个中除了最大值, 要选择出一个是重复的数, 即\(C^1_{n-2}\), 那么, 可供我们自由排列的数就只有\(n-3\)个, 假设在最大值左边有\(i\)个, 即\(\sum^{n-3}_{i=0}C^i_{n-3} = 2^{n-3}\)

#include<bits/stdc++.h>
using namespace std;
#define ms(x,y) memset(x, y, sizeof(x))
#define lowbit(x) ((x)&(-x))
typedef long long LL;
typedef pair<int,int> pii;

const int N = 200000 + 5;
const int MOD = (int)998244353;
LL F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘 
void init(){
    inv[1] = 1;
    for(int i = 2; i < N; i ++){
        inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
    }
    F[0] = Finv[0] = 1;
    for(int i = 1; i < N; i ++){
        F[i] = F[i-1] * 1ll * i % MOD;
        Finv[i] = Finv[i-1] * 1ll * inv[i] % MOD;
    }
}
LL comb(int n, int m){//comb(n, m)就是C(n, m) 
    if(m < 0 || m > n) return 0;
    return F[n] * 1LL * Finv[n - m] % MOD * Finv[m] % MOD;
}

LL quick_pow(LL a, LL b) {
    if(b < 0) return 0;
    LL ret = 1;
    while(b) {
        if(b & 1) ret = (ret * a) % MOD;
        a = (a * a) % MOD;
        b >>= 1;
    }
    return ret;
}

void run_case() {
    int n, m;
    cin >> n >> m;
    init();
    LL ans = 0;
    ans = comb(m, n-1) % MOD;
    ans = (ans * (n-2)) % MOD;
    ans = (ans * quick_pow(2, n-3)) % MOD;
    cout << ans;
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0);
    cout.flags(ios::fixed);cout.precision(2);
    //int t; cin >> t;
    //while(t--)
    run_case();
    cout.flush();
    return 0;
}
posted @ 2020-03-13 16:37  GRedComeT  阅读(117)  评论(0编辑  收藏  举报