1. 程式人生 > >codeforces 451E Devu and Flowers

codeforces 451E Devu and Flowers

1題目大意:給出n個盒子,每個盒子裡有val[i]個球,想要拿出s個球,從每個盒子裡拿出相同的球算同種方案,求方案數。

首先對於式子x_{1}+x_2+x_3+x_4+......x_n=s的非負整數解個數為C_{n+s-1}^{n-1},考慮隔板法,將s個東西分成n份,允許有空

相當於在s-1個空中放n-1個隔板,有空的盒子可以相當於先加上盒子個數個小球,真實計算是再減去,所以就是n+s個東西

其中n+s-1個空選擇n-1個放。但是這道題有個數限制,所以不合法的情況就是其中的盒子放多了,因為放多了1個就不合法

所以設不合法的情況為val[i]+1(PS:之後再放自己裡都不合法,所以不必計算,也不少不重複)。那麼減去所有1個盒子放

多的情況時,多減去了2個放多的情況。所以要用容斥原理,減去奇數個放多的情況,對於組合數可以列舉,因為n≤20。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define mode 1000000007
using namespace std;
typedef long long ll;
int n;
ll s,val[25],ans,now,gs,niv[25];
ll read()
{
    ll x=0,f=1;char ch;
    while(ch<'0'||ch>'9')  {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}
ll C(ll x,ll y)
{
    if(x<y)return 0;
    ll as=1;
    for(ll i=x-y+1;i<=x;i++)
    {
        as=(as*(i%mode))%mode;
    }
    return as*niv[y]%mode;
}
int main()
{
    scanf("%d%lld",&n,&s);
    for(int i=1;i<=n;i++)
    {
        val[i]=read();
    }
    niv[1]=1;
    for(int i=2;i<=n;i++)niv[i]=(mode-mode/i)*niv[mode%i]%mode;
    niv[0]=1;
    for(int i=1;i<=n;i++)niv[i]=niv[i-1]*niv[i]%mode;
 	for(int i=0;i<=(1<<n)-1;i++)
 	{
 		gs=0,now=0; 
        for(int j=1;j<=n;j++)
        {
            if(1<<(j-1)&i)
            {
                gs++;now+=val[j]+1;
            }
        }	
        if(gs%2==0)ans+=C(s+n-now-1,n-1),ans%=mode;
        else ans-=C(s+n-now-1,n-1),ans%=mode;
    }
 	printf("%lld",(ans%mode+mode)%mode);
    return 0;
}