CodeForces-451E:Devu and Flowers (母函数+组合数+Lucas定理)
Devu wants to decorate his garden with flowers. He has purchased n boxes, where the i-th box contains fi 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 s 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 (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.
Input
The first line of input contains two space-separated integers n and s (1 ≤ n ≤ 20, 0 ≤ s ≤ 1014).
The second line contains n space-separated integers f1, f2, ... fn (0 ≤ fi ≤ 1012).
Output
Output a single integer — the number of ways in which Devu can select the flowers modulo (109 + 7).
Example
2 3
1 3
2
2 4
2 2
1
3 5
1 3 2
3
题意:给定N种花,每种花有Fi朵,现在要取M朵花,问有多少种方案。
思路:母函数或者容斥定理,当然,学过数学竞赛的应该知道结论,怎么用容斥定理去做。我更倾向于用母函数去做,虽然方程是一样的,但是感觉后者好理解一些。
母函数 : (1+X^1...+X^f1)*(1+X^1...+Xf2)*...(1+X^1...+X^fn)
=(1-X^(f1+1))*(1-X^(f2+1))...(1-X^(fn+1)) / ((1-X)^N)
=(1-X^(f1+1))*(1-X^(f2+1))...(1-X^(fn+1)) * ((1+X^1+X^2+...)^N)。
对于前面部分((1-X^(f1+1))*(1-X^(f2+1))...(1-X^(fn+1)) )可以枚举O(2^N),然后剩余部分,就是组合问题了,假设前面的和为S,那么就要在后面部分(((1+X^1+X^2+...)^N))拿M-S个,然后根据组合公式,C(M-S+N-1,N-1)。
组合公式那里利用Lucas可以降低复杂度,但是我还是觉得复杂度过不去,O(N * 2^N *Mod *LogMod )可能是数据水了,然后只花了900ms。
容斥定理:假设没有限制F,则得到ans=C(M+N-1,N-1)。但是有限制后有的会超过Fi,枚举超过的那几个,blabla,大概是这个方向啦,具体的我也没有细究。
#include<cmath> #include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int Mod=1e9+7; int N; ll M,f[22],ans; ll qpow(ll a,ll x) { ll res=1; a%=Mod; while(x){ if(x&1LL) res=res*a%Mod; a=a*a%Mod; x>>=1; } return res; } ll Com(ll a,ll b) { ll res=1,fm=1,fz=1; if(a-b<b) b=a-b; for(int i=1;i<=b;i++){ fm=fm*i%Mod; fz=fz*(a-i+1)%Mod; } res=fz*qpow(fm,Mod-2)%Mod; return res; } ll Lucas(ll a,ll b) { if(b==0) return 1; return Lucas(a/Mod,b/Mod)*Com(a%Mod,b%Mod)%Mod; } void solve() { for(int i=0;i<(1<<N);i++){ ll sig=1,sum=M; for(int j=0;j<N;j++){ if((1<<j)&i) sum-=(f[j]+1),sig*=-1; } if(sum<0) continue; ans=(ans+sig*Lucas(N+sum-1,N-1))%Mod; } } int main() { scanf("%d%lld",&N,&M); for(int i=0;i<N;i++) scanf("%lld",&f[i]);//,sum+=f[i]; solve(); printf("%lld\n",(ans%Mod+Mod)%Mod); return 0; }