214. Devu和鲜花
Devu 有 N 个盒子,第 i 个盒子中有 Ai 枝花。
同一个盒子内的花颜色相同,不同盒子内的花颜色不同。
Devu 要从这些盒子中选出 M 枝花组成一束,求共有多少种方案。
若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。
隔板法 + 容斥原理
设 \(x_i\) : 第 \(i\) 个盒子拿出的数量. 有 \(x_i \le A_i\), 且 :
\(x_1+x_2+x_3+...+x_n=m\).
令 \(y_i=x_i+1\), 则 \(y_1+y_2+y_3+...+y_n=m-n\).
先不考虑限制, 运用隔板法 : 一共有 \(C_{m+n-1}^{n-1}\) 种可能.
不妨设 \(S_i\) : 第 \(i\) 个盒子超出 \(A_i\) 的集合.
于是答案 : \(ans=C_{m+n-1}^{n-1}-(S_1\cup S_2 \cup S_3 \cup ... \cup S_n)\).
后面那一坨就是容斥原理.
怎么求 \(S_i\) ? \(x_i\ge A_i+1 \Longleftrightarrow y_i\ge A_i +2\), 所以有 :
\(y_1+y_2+y_3+...+y_n=m+n-(A_i+1)\), 继续用隔板法 : \(S_i = C_{m+n-A[i]-1}^{n-1}\)
代码 :
#include <bits/stdc++.h> using namespace std; #define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0); inline int lowbit(int x) { return x & (-x); } #define ll long long #define ull unsigned long long #define pb push_back #define PII pair<int, int> #define VIT vector<int> #define x first #define y second #define inf 0x3f3f3f3f const int N = 20, mod = 1e9 + 7; ll a[N]; ll down; ll qmi(ll a, ll k) { ll res = 1; while (k) { if (k & 1) res = res * a % mod; a = a * a % mod; k >>= 1; } return res; } ll C(ll a, ll b) { if (a < b) return 0; ll up = 1; for (ll i = a; i > a - b; --i) up = i % mod * up % mod; return up * down % mod; } int main() { //freopen("in.txt", "r", stdin); IO; down = 1; ll n, m; cin >> n >> m; for (ll i = 1; i <= n - 1; ++i) down = down * i % mod; down = qmi(down, mod - 2); for (int i = 0; i < n; ++i) cin >> a[i]; ll ans = C(m + n - 1, n - 1); for (int i = 1; i < 1 << n; ++i) { int sign = 1; ll t = m + n - 1; for (int j = 0; j < n; ++j) if (i >> j & 1) { sign *= -1; t -= a[j] + 1; } ans = (ans + sign * C(t, n - 1)) % mod; } ans = (ans + mod) % mod; cout << ans << '\n'; return 0; }