【多重集组合数】 Devu and Flowers

传送门

题意

给定\(n\)\(s\),表示有\(n\)个箱子要取\(s\)朵花,每个箱子表示一个种类的花,每个箱子中花的数量分别是

\[f_{1} , f_{2} , \dots , f_{n} \]

求出不同的选取方案

数据范围

\(1 \leq n \leq 20\)
\(0 \leq s \leq 10^{14}\)
\(0 \leq f_{i} \leq 10^{12}\)

题解

多重集合的组合数模板,容斥原理通过二进制数表示选择的个数

Code

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=30,mod=1e9+7;
ll f[N];
ll down;
ll quick_pow(ll a, ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll C(ll a,ll b){
    if(a<b) return 0;
    ll res=1;
    for(ll i=a;i>a-b;i--) res=i%mod*res%mod;
    return res*down%mod;
}
int main(){
    ll n, s;
    cin >> n >> s;
    for (int i = 0; i < n; i ++ ) cin >> f[i];
    down=1;
    for (ll j = 1; j <= n - 1; j ++ ) down = j * down % mod;
    down = quick_pow(down, mod - 2);

    int res = 0;
    for(int i=0;i<1<<n;i++){
        ll sign=1;
        ll a=n+s-1;
        for(int k=0;k<n;k++){
            if(i>>k&1){
                sign*=(-1);
                a-=f[k]+1;
            }
        }
        res = (res + C(a, n-1) * sign) % mod;
    }
    cout<<(res+mod)%mod<<endl;
}
posted @ 2020-05-20 22:11  Hyx'  阅读(153)  评论(0编辑  收藏  举报