1.多重集的组合数
这里问题一般的描述为:
算法竞赛进阶指南上有详细的推导。
例题1: CF 451E Devu and Flowers
直接带公式,但本题 m 太大,先用Lucas对m取模,再转换成排列再乘以逆元就可以了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; ll f[30]; const ll mod = 1e9 + 7; ll inv[30]; ///C(y,x) ll quick_pow(ll a, ll n) { ll res = 1; while(n) { if(n & 1LL) res = res * a % mod; n >>= 1LL; a = a * a % mod; } return res; } ll C(ll y, ll x) { // printf("%lld %lld\n", y,x); if(y < 0 || x < 0 || y < x) return 0; y %= mod; if(y == 0 || x == 0) return 1; ll res = 1; for(int i = 0; i < x; i++) { res = res * (y - i) % mod; } for(int i = 1; i <= x; i++) { res = res * inv[i] % mod; } // printf("%lld\n", res); return res; } int main() { ll n, m; cin >> n >> m; for(int i = 0; i <= 20; i++) { inv[i] = quick_pow(i, mod - 2); // printf("%lld\n", inv[i]); } for(int i = 1; i <= n; i++) cin >> f[i]; ll ans = 0; for(int x = 0; x < (1 << n); x++) { if(x == 0) { ans = (ans + C(n + m - 1, n - 1)) % mod; } else { int p = 0; ll t = n + m; for(int i = 0; i < n; i++) { if((1 << i) & x) { t -= f[i + 1]; p++; } } t -= (p + 1); if(p & 1) { ans = (ans - C(t, n - 1) + mod) % mod; } else { ans = (ans + C(t, n - 1)) % mod; } } // cout << ans << endl; } cout << ans << endl; return 0; }