CF451E Devu and Flowers

题目描述:

Devu想用花去装饰他的花园,他已经购买了n个箱子,第i个箱子有fi朵花,在同一个的箱子里的所有花是同种颜色的(所以它们没有任何其他特 征)。另外,不存在两个箱子中的花是相同颜色的。 现在Devu想从这些箱子里选择s朵花去装饰他的花园,Devu想要知道,总共有多少种方式从这些箱子里取出这么多的花?因为结果有可能会很大,结果需要 对1000000007取模。 Devu认为至少有一个箱子中选择的花的数量不同才是两种不同的方案。

题解:

乍一看很难,但是化成容斥将会非常好做。

由于n极小,所以可以枚举每一篮子花是否超出当前fi,然后通过容斥有:

ans = g0 - g1 + g2 - g3 + g4 - g5 +……

其中gi表示有i个篮子超限时方式总数。

一定要多取余:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define MOD 1000000007
ll n;
ll s,a[25],ans;
ll fast(ll x,int y)
{
    ll ret = 1ll;
    while(y)
    {
        if(y&1)ret=ret*x%MOD;
        x=x*x%MOD;
        y>>=1;
    }
    return ret;
}
ll C(ll x,ll y)
{
    ll sx=1ll,sy=1ll;
    for(ll i=1ll;i<=y;i++)
    {
        sx=(sx*(x%MOD-i%MOD+1ll)%MOD+MOD)%MOD;
        sy=sy*(i%MOD)%MOD;
    }
    return (fast(sy,MOD-2)*sx%MOD+MOD)%MOD;
}
int main()
{
    scanf("%lld%lld",&n,&s);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i=0;i<(1<<n);i++)
    {
        ll f=1ll,g=s;
        for(int j=0;j<n;j++)
        {
            if(i&(1<<j))
            {
                g-=a[j+1]+1ll;
                f*=-1;
            }
        }
        if(g<0)continue;
        ans=((ans+f*C(g+n-1ll,n-1ll)%MOD)%MOD+MOD)%MOD;
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-11-02 18:31  LiGuanlin  阅读(185)  评论(6编辑  收藏  举报