1. 程式人生 > >CF451E Devu and Flowers 解題報告

CF451E Devu and Flowers 解題報告

CF451E Devu and Flowers

題意:

\(Devu\)\(N\)個盒子,第\(i\)個盒子中有\(c_i\)枝花。同一個盒子內的花顏色相同,不同盒子的花顏色不同。\(Devu\)要從中選出\(M\)枝花,求有多少種方案,對\(10e9+7\)取模。

資料範圍

\(1 \le N \le 20,0 \le M \le 10^{14},0 \le c_i \le 10^{12}\)


其實就是求多重集組合數的模板題。

可以看看我寫的部落格

一些注意點,發現直接求會爆\(long long\)\(lucas\)一下免得爆了

注意\(M\)很大\(N\)很小,所以先把\((M-N)!\)

除掉再算複雜度就是對的了


Code:

#include <cstdio>
#define ll long long
const ll mod=1e9+7;
ll quickpow(ll d,ll k)
{
    ll f=1;
    while(k)
    {
        if(k&1) f=f*d%mod;
        d=d*d%mod;
        k>>=1;
    }
    return f;
}
ll cal(ll r,ll l)
{
    ll s=1;
    for(ll i=r;i>l;i--) (s*=i)%=mod;
    return s;
}
ll inv[22];
ll C(ll m,ll n)
{
    if(m<n) return 0;
    if(n==0) return 1;
    if(m<mod) return cal(m,m-n)*inv[n]%mod;
    return C(m/mod,n/mod)*C(m%mod,n%mod)%mod;
}
ll n,s,f[23];
int main()
{
    scanf("%lld%lld",&n,&s);
    ll fac=1;
    for(ll i=1;i<=n;i++)
    {
        fac=fac*i%mod;
        inv[i]=quickpow(fac,mod-2);
        scanf("%lld",f+i);
    }
    ll ans=0;
    for(int i=0;i<1<<n;i++)
    {
        ll m=s+n-1,cnt=0;
        for(int j=0;j<n;j++)
            if(i>>j&1)
                m-=f[j+1],cnt++;
        (ans+=(cnt&1?-1ll:1ll)*C(m-cnt,n-1))%=mod;
    }
    printf("%lld\n",(ans%mod+mod)%mod);
    return 0;
}

2018.10,17