【JSOI 2011】 分特产

【题目链接】

           点击打开链接

【算法】

           考虑求每个人可以不分的方案

           那么,对于每件物品,我们把它分成n份,每一份对应分给每一个人,有C(a[i]+n-1,m-1)种方案,而总方案数就是每种

           物品方案数的乘积

           然后,根据容斥原理,ans = 至少0人没分到特产 - 至少1人没分到特产 +  ... - C(m,m) * 没有一人分到

           特产

【代码】

            

#include<bits/stdc++.h>
using namespace std;
#define MAXN 2010
const long long P = 1000000007 ;

int i,n,m;
long long a[MAXN],fac[MAXN],inv[MAXN];
long long ans;

inline long long power(long long a,long long n)
{
    long long ans = 1,b = a;
    while (n > 0)
    {
        if (n & 1) ans = (ans * b) % P;
        b = (b * b) % P;
        n >>= 1;
    }
    return ans;
}
inline void init()
{
    int i;
    fac[0] = 1;
    for (i = 1; i < MAXN; i++) fac[i] = fac[i-1] * i % P;
    inv[MAXN-1] = power(fac[MAXN-1],P-2);
    for (i = MAXN - 2; i >= 1; i--) inv[i] = inv[i+1] * (i + 1) % P;
    inv[0] = 1;
}
inline long long C(int n,int m)
{
    return fac[n] * inv[n-m] % P * inv[m] % P;
}
inline long long calc(int x)
{
    int i;
    long long ans = 1;
    for (i = 1; i <= m; i++) ans = (ans * C(a[i]+n-x-1,n-x-1)) % P;
    return ans;    
}

int main()
{
    
    init();
    scanf("%d%d",&n,&m);
    for (i = 1; i <= m; i++) scanf("%d",&a[i]);
    for (i = 0; i <= n; i++)
    {
        if (i % 2 == 0) ans = (ans + C(n,i) * calc(i)) % P;
        else ans = (ans - (C(n,i) * calc(i) % P) + P) % P;
    }
    printf("%lld\n",ans);
    
    return 0;    
} 

 

posted @ 2018-05-29 21:03  evenbao  阅读(119)  评论(0编辑  收藏  举报