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 }
codeforces 451 E. Devu and Flowers
posted @ 2018-08-30 09:14  KingSann  阅读(134)  评论(0)    收藏  举报