[CF451E] Devu and Flowers - 容斥计数
Description
(n) 种花每种 (f_i) 个,求选出 (s) 朵花的方案。不一定每种花都要选到。 (nle 20)
Solution
本质上是带限制的多重集合排列问题
考虑容斥,钦定若干种爆掉(就是我们强行至少选 (f_i+1)),然后算出一个数,给它个容斥系数再求和
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, s, f[25];
const int mod = 1e9 + 7;
int qpow(int p, int q)
{
return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
}
int inv(int p)
{
return qpow(p, mod - 2);
}
int fac(int n)
{
if (n == 0)
return 1;
return fac(n - 1) * n % mod;
}
int func(int n, int s, int sum)
{
if (s - sum + 1 <= 0)
return 0;
int ans = 1;
for (int i = 1; i <= n - 1; i++)
ans = (ans * ((s - sum + i) % mod) % mod) % mod;
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
int ans = 0;
cin >> n >> s;
for (int i = 1; i <= n; i++)
cin >> f[i];
for (int i = 0; i < 1 << n; i++)
{
int sum = 0;
for (int j = 1; j <= n; j++)
{
if (i & (1 << (j - 1)))
{
sum += 1 + f[j];
}
}
ans += (__builtin_popcount(i) & 1 ? -1 : 1) * func(n, s, sum);
ans %= mod;
ans += mod;
ans %= mod;
}
cout << ans * inv(fac(n - 1)) % mod << endl;
}