codeforces 451 E. Devu and Flowers
有$n$种花,第$i$种有$f_i$朵,求从中选出$s$朵花的方案数
$1 \le n \le 20$
$0 \le s \le 10^{14}$
$0 \le f_i \le 10^{12}$
这不就是某经典容斥模型吗……
有$n$个整数变量,第$i$个变量的取值范围是$[0,f_i]$,求$\sum_{i=1}^{n}x_i=s$的方案数
枚举哪些变量超过限制,然后让它们强制变为$f_i+1+y_i$,这样就是一个没有限制的求方案数了,答案为${s+n-1 \choose n-1}$

1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int mod = 1e9 + 7; 5 int n; 6 ll sum, f[21], ans, inv[21]; 7 8 ll pw(ll a, ll b) { 9 ll r = 1; 10 for( ; b ; b >>= 1, a = a * a % mod) if(b & 1) r = r * a % mod; 11 return r; 12 } 13 14 int main() { 15 cin >> n >> sum; 16 for(int i = 0 ; i < n ; ++ i) cin >> f[i], inv[i] = pw(i, mod - 2); 17 for(int s = 0 ; s < (1 << n) ; ++ s) { 18 int cnt = 0; 19 ll tot = 0; 20 for(int i = 0 ; i < n ; ++ i) { 21 if((s >> i) & 1) { 22 ++ cnt; 23 tot += f[i] + 1; 24 if(tot > sum) { tot = -1; break; } 25 } 26 } 27 if(tot == -1) continue; 28 tot = sum - tot; 29 // C(tot + n - 1, n - 1) = (tot + n - 1)! / (n - 1)! / (tot)! 30 ll tmp = 1; 31 for(ll i = tot + 1 ; i <= tot + n - 1 ; ++ i) (tmp *= i % mod) %= mod; 32 for(ll i = 1 ; i <= n - 1 ; ++ i) (tmp *= inv[i] % mod) %= mod; 33 if(tmp < 0) cout << "tmp = " << tmp << endl; 34 ans = (ans + (cnt & 1 ? -1 : 1) * tmp) % mod; 35 } 36 ans = (ans % mod + mod) % mod; 37 cout << ans << endl; 38 }