bzoj 4710 分特产

有 $n$ 个人,$m$ 种物品,每种物品有 $a_i$ 个,求每个人至少分到一个的方案数

$n,m,a_i leq 2000$

sol:

比上一个题简单一点

还是考虑容斥

每个人至少分到一个 = 随便选 - 至少 1 个人没分到 + 至少 2 个人没分到 - 至少 3 个人没分到 + ...

至少 $i$ 个人没分到就是选出 $i$ 个人分不到,然后对于每种物品,要把它分给剩下的 $(n-i)$ 个人,注意到物品间是相同的,人是不同的,插板就可以了

最后答案是 $sumlimits_{i=1}^n (-1)^i imes C_{n}^i imes prodlimits_{j=1}^m C_{a_j+n-i-1}^{n-i-1}$

#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read()
{
    int x = 0,f = 1;char ch = getchar();
    for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f;
    for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int mod = 1000000007,maxn = 1000000 + 50;
int n,m,a[maxn];
int fac[maxn],ifac[maxn];
inline int ksm(int x,int t)
{
    int res = 1;
    while(t)
    {
        if(t & 1)res = 1LL * res * x % mod;
        x = 1LL * x * x % mod;
        t = t >> 1;
    }return res;
}
inline int C(int n,int m)
{
    if(n < 0 || m < 0 || n < m)return 0;
    return (((1LL * ifac[m] * ifac[n - m]) % mod) * fac[n]) % mod;
}
int main()
{
    ifac[0] = fac[0] = 1;for(int i=1;i<=maxn-10;i++)fac[i] = (1LL * fac[i - 1] * i) % mod;
    ifac[maxn - 10] = ksm(fac[maxn - 10],mod - 2);for(int i=maxn-11;~i;i--)ifac[i] = (1LL * ifac[i + 1] * (i + 1)) % mod;
    //cout<<1LL * ifac[6] * fac[6]<<endl;
    n = read(),m = read();
    for(int i=1;i<=m;i++)a[i] = read();
    int ans = 0;
    for(int i=0;i<n;i++)
    {
        int tmp = C(n,i);
        for(int j=1;j<=m;j++)
            tmp = 1LL * tmp * C(n - i - 1 + a[j],a[j]) % mod;
        //cout<<tmp<<endl;
        (ans += ((i & 1) ? -1 : 1) * tmp) %= mod;
    }
    ans = (ans + mod) % mod;
    cout<<ans<<endl;
}
View Code
原文地址:https://www.cnblogs.com/Kong-Ruo/p/10231537.html