CodeForces

题意:有N个盒子,每个盒子里有fi 朵花,求从这N个盒子中取s朵花的方案数。两种方法不同当且仅当两种方案里至少有一个盒子取出的花的数目不同。

分析:对 有k个盒子取出的数目超过了其中的花朵数,那么此时的方案数根据放球模型是C(N+t-1,N-1),其中t是s-(k个盒子超过其数目的最小数量)。显然t<0该方案不存在。

而k个盒子超过其数目的最小数量 是 对应盒子数+1的和。

因为t的值可能很大,所以需要用Lucas定理计算组合数。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;
const int mod = 1e9+7;
LL Pow(LL x, LL n, LL p)
{
    LL res=1;
    while(n)
    {
        if(n&1) res=x*res%p;
        x=x*x%p;
        n>>=1;
    }
    return res;
}

LL Lucas(LL n, LL k, LL p)
{
    if(k>n-k) k=n-k;
    LL res=1;
    while(n&&k){
        LL n0=n%p, k0=k%p;
        LL a=1,b=1;
        for(LL i=n0; i>n0-k0; i--) a=a*i%p;
        for(LL i=1; i<=k0; i++) b=b*i%p;
        res = res*a*Pow(b, p-2, p)%p;
        n/=p; k/=p;
    }
    return res;
}

LL f[30];
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    LL n,s;
    while(scanf("%lld %lld",&n,&s)==2){
        for(int i=0;i<n;++i){
            scanf("%lld", &f[i]);
        }
        LL up = 1LL << n;
        LL ans = Lucas(n+s-1,n-1,mod);
        for(int i=1;i<up;++i){
            int bit = 0;
            LL t= s;
            for(int j=0;j<n;++j){
                if(i &(1<<j)){
                    bit++;
                    t -= f[j] + 1;
                }    
            }
            if(t<0) continue;
            if(bit & 1) ans = (ans+mod -Lucas(n+t-1,n-1,mod))%mod;
            else ans = (ans+Lucas(n+t-1,n-1,mod))%mod;
        }
        printf("%lld
",ans);
    }
    return 0;
}
为了更好的明天
原文地址:https://www.cnblogs.com/xiuwenli/p/9512523.html