CF451E Devu and Flowers
题目描述
Devu wants to decorate his garden with flowers. He has purchased nn boxes, where the ii -th box contains f_{i}f**i flowers. All flowers in a single box are of the same color (hence they are indistinguishable). Also, no two boxes have flowers of the same color.
Now Devu wants to select exactly ss flowers from the boxes to decorate his garden. Devu would like to know, in how many different ways can he select the flowers from each box? Since this number may be very large, he asks you to find the number modulo (10^{9}+7)(109+7) .
Devu considers two ways different if there is at least one box from which different number of flowers are selected in these two ways.
输入格式
The first line of input contains two space-separated integers nn and ss ( 1<=n<=201<=n<=20 , 0<=s<=10^{14}0<=s<=1014 ).
The second line contains nn space-separated integers f_{1},f_{2},... f_{n}f1,f2,... f**n ( 0<=f_{i}<=10^{12}0<=f**i<=1012 ).
输出格式
Output a single integer — the number of ways in which Devu can select the flowers modulo (10^{9}+7)(109+7) .
题意翻译
题目描述
Devu想用花去装饰他的花园,他已经购买了n个箱子,第i个箱子有fi朵花,在同一个的箱子里的所有花是同种颜色的(所以它们没有任何其他特征)。另外,不存在两个箱子中的花是相同颜色的。 现在Devu想从这些箱子里选择s朵花去装饰他的花园,Devu想要知道,总共有多少种方式从这些箱子里取出这么多的花?因为结果有可能会很大,结果需要对1000000007取模。 Devu认为至少有一个箱子中选择的花的数量不同才是两种不同的方案。 输入输出格式 输入格式:
第一行包含两个用空格分开的整数n和s 第二行包含n个用空格分开的整数fi 输出格式:
输出一个整数,Devu的方案数对1000000007取模 说明
样例1:选3朵花两种方案:1,2 和 0,3 样例2:选4朵花只有一种方案:2,2 样例3:选5朵花三种方案:1,2,2 和 0,3,2 和 1,3,1
感谢@Hello灬BABY灬OvO 提供的翻译
题解:
排列组合这个地方的确比较难理解,来给大家用大白话讲一下。
多重集排列组合。
不妨反着来:对于有(N)种元素的多重集(S),选(K)个元素,注意是个不是种,的可行方案数。可以变成:现在有(N)个篮子,把(K)个元素扔进这些篮子里的方案数。
注意,这种是特殊情况,也就是说,每种元素无限多个可供挑选。
这样的话,用隔板法解决问题。
容易得出,答案也就是(C_{N+K-1}^{N-1})。
解释一下,现在有(K)个元素,分成(N)堆,也就是要往里插入(N-1)块板。按理讲应该是(C_{K+1}^{N-1}),但是因为允许有空集,也就是不插,那么就相当于每块板子插进去之后又产生了新元素,所以是这个答案。
那么,根据多重集的限制,现在每种元素有一个数量上限,怎么办呢?
很简单,采用容斥原理。关于容斥原理,请见:
上限是“至多放(f[i])个”,那么如果我往这个里面放(f[i]+1)个,是不是就不合法了?
把不合法的减去即可。
因为这道题N只有20,所以考虑状压,表示当前这个集合超没超。
最后根据容斥,如果当前状态1的个数是奇数,就要减去,是偶数,就要加上。
代码:
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=25;
const int mod=1e9+7;
int n;
ll s;
ll f[maxn],inv[maxn];
ll calc(ll n,ll m)
{
if(n<0||m<0||n<m)
return 0;
n%=mod;
if(n==0||m==0)
return 1;
ll ret=1;
for(int i=0;i<m;i++)
ret=(ret*(n-i))%mod;
for(int i=1;i<=m;i++)
ret=(ret*inv[i])%mod;
return ret;
}//n中选m的组合数
ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret=(ret*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ret;
}
int main()
{
scanf("%d%lld",&n,&s);
for(int i=1;i<=n;i++)
scanf("%lld",&f[i]);
for(int i=1;i<=20;i++)
inv[i]=qpow(i,mod-2);
ll ans=calc(n+s-1,n-1)%mod;
for(int i=1;i<(1<<n);i++)
{
ll tot=n+s;
int p=0;
for(int j=0;j<n;j++)
if(i>>j&1)
{
p++;
tot-=(f[j+1]+1);
}
tot--;
if(p&1)
ans=(ans-calc(tot,n-1))%mod;
else
ans=(ans+calc(tot,n-1))%mod;
}
printf("%lld
",(ans+mod)%mod);
return 0;
}