Devu和鲜花
Devu有N个盒子,第i个盒子中有Ai枝花。
同一个盒子内的花颜色相同,不同盒子内的花颜色不同。
Devu要从这些盒子中选出M枝花组成一束,求共有多少种方案。
若两束花每种颜色的花的数量都相同,则认为这两束花是相同的方案。
结果需对109+7取模之后方可输出。
输入格式
第一行包含两个整数N和M。
第二行包含N个空格隔开的整数,表示A1,A2,…,AN。
输出格式
输出一个整数,表示方案数量对109+7取模后的结果。
数据范围
1
≤
N
≤
20
1≤N≤20
1≤N≤20,
0
≤
M
≤
1
0
14
0≤M≤10^{14}
0≤M≤1014,
0
≤
A
i
≤
1
0
12
0≤Ai≤10^{12}
0≤Ai≤1012
输入样例:
3 5
1 3 2
输出样例:
3
题解:
这道题如果没有限制,那么我们就是x元一次方程求解(根据题目中的背景我们需要保证每个未知数是正整数,所以我们两边同时加上一个N),也就是隔板法可以做。这里加了限制,所以我们可以用所有合法的情况减去所有不合法的情况的并集合。
根据容斥原理展开,我们就可以算了。因为N比较小所以容斥原理
2
n
2^n
2n可以满足。
不合法情况怎么判断昵?比如我们没有限制就是每个盒子有无穷支花,但是其实只有a个,所以我们拿a+1支花就不合法了。意思是每个盒子拿容量+1支花就不合法了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20, mod = 1e9 + 7;
int A[N],down=1;
int q_pow(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1) res = res * a % mod;
a = a * a % mod;
k >>= 1;
}
return res;
}
int C(int a, int b)
{
if (a < b) return 0;
int up = 1;
for (int i = a; i > a - b; i -- ) up = i % mod * up % mod;
return (int)up * down % mod; // 费马小定理
}
signed main()
{
int n,m; cin>>n>>m;
for(int i=0;i<n;i++) scanf("%lld",A+i);
int res=0;
for(int i=1;i<=n-1;i++) down=i*down%mod;
down=q_pow(down,mod-2);
for(int i=0;i<(1<<n);i++){
int a=n+m-1,b=n-1;
int fuhao=1;
for(int j=0;j<n;j++){
if(i>>j&1){
a-=A[j]+1;
fuhao*=-1;
}
}
res=(res+C(a,b)*fuhao)%mod;
}
cout<<(res+mod)%mod<<endl;
}