首先我先提出一个模型
b个盒子里面每个盒子里面有无限多个花
问取m支有多少种取法
我们设在第一个盒子取x1,第二个x2 x3 …xn
所以x1 + x2 + x3 +…+ xn = m
当我们取每个盒子至少为1的时候即为
(x1 + 1)+(x2+1)+…+(xn + 1) = m + n;
此时我们可以采取隔板法
n+m个球 n + m - 1 个位置 隔 n - 1块板即
cal(n+m-1,n-1)即为答案
转述到这道题每个盒子都有限制
即x1 <= a1 x2 <= a2… xn <= an;
所以我们可以采取容斥原理
即我们取到 x1 >= a1 + 1,x2 >= a2 + 1 … xn >= an + 1
这些不满足条件的情况
我们设当x1 >= a1 + 1时满足条件的集合为s1
x2 >= a2 + 1 满足条件的集合为s2
xn >= xn + 1 满足条件的集合为sn
有容斥原理可以得 ans = s1 + s2 + … + sn - s1∩s2 - s1∩s3… + s1 ∩ s2 ∩ s3等等
此时我们只需用一个2进制枚举答案即可
由于n小于等于20 2^20次在时间范围内;
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 25,mod = 1e9 + 7;
ll a[N];
ll cal(ll a,ll b){
if(a < b) return 0;
ll x = 1;
for(ll i = a; i > a - b; i--){
x *= (i % mod);
x %= mod;
}
return x;
}
ll qmi(ll a,ll b){
ll s = 1;
while(b){
if(b & 1) s = s * a % mod;
a = a * a % mod;
b >>= 1;
}
return s;
}
int main(){
int n;ll m;
cin >> n >> m;
for(int i = 0; i < n; i++){
cin >> a[i];
}
ll s = 1;
for(int i = 1; i <= n - 1; i++){
s = s * i % mod;
}
s = qmi(s,mod - 2);
ll ans = 0;
for(int i = 0; i < (1 << n); i++){
ll h = n + m - 1;int sign = 1;
for(int j = 0; j < n; j++){
if(i & (1 << j)){
h -= a[j] + 1;
sign *= -1;
}
}
h = cal(h,n - 1);
ans += h * s * sign % mod;
ans %= mod;
}
cout << (ans % mod + mod) % mod << endl;
return 0;
}