hiho1804 - 整数分解、组合数、乘法逆元

题目链接

题目叙述很啰嗦,可以简化为:n个球[1-1e5],放到m个不同的桶里,一共多少种不同的放法。【桶里可以不放】

------------------------------------------------------------------------------------------------

解C(n+m-1, m-1)

由于m,n可能很大,所以需要用逆元。扩展欧几里得。

 

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int N = 200001;
LL MOD = 1e9 + 7;
LL F[N], Inv[N];

LL exgcd(LL a, LL b, LL& x, LL& y){
    if (b == 0){
        x = 1, y = 0; return a;
    }
    else{
        auto gcd = exgcd(b, a%b, y, x);
        y -= (a / b) * x;
        return gcd;
    }
}

int main(){
    LL n, k; cin >> n >> k; 
    int left = n - k, last = MOD, seg = 0;
    n += MOD;
    for (int i = 0; i < left; ++i){
        int val; scanf("%d", &val);
        if (val>last){
            last = val;
        }
        else{
            ++seg;
            n -= last;
            last = val;
        }
    } n -= last;
    
    if (n < 0){
        puts("No");
    }
    else{
        F[0] = 1; for (int i = 1; i < N; ++i){
            F[i] = (i * F[i - 1]) % MOD;
        }
        LL nouse; exgcd(F[N - 1], MOD, Inv[N-1], nouse); 
        while (Inv[N - 1] < 0) Inv[N - 1] += MOD;
        
        for (int i = N - 2; i; --i){
            Inv[i] = (Inv[i + 1] * (i + 1)) % MOD;
        }

        std::cout << (F[n + seg - 1] * Inv[n]) % MOD*Inv[seg - 1] % MOD << std::endl;
        //C(n+seg-1,seg-1);
    }
}

猜你喜欢

转载自www.cnblogs.com/redips-l/p/9502413.html