• BZOJ


    JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们。
    JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望任
    何一个同学因为没有拿到特产而感到失落,所以每个同学都必须至少分得一个特产。
    例如,JYY 带来了2 袋麻花和1 袋包子,分给A 和B 两位同学,那么共有4 种不同的
    分配方法:
    A:麻花,B:麻花、包子
    A:麻花、麻花,B:包子
    A:包子,B:麻花、麻花
    A:麻花、包子,B:麻花
     

    Input

    输入数据第一行是同学的数量N 和特产的数量M。
    第二行包含M 个整数,表示每一种特产的数量。
    N, M 不超过1000,每一种特产的数量不超过1000
     

    Output

    输出一行,不同分配方案的总数。由于输出结果可能非常巨大,你只需要输出最终结果
    MOD 1,000,000,007 的数值就可以了。
     

    Sample Input

    5 4
    1 3 3 5

    Sample Output

    384835


    题解:
      首先我们要知道一个结论,把m相同的物品分给n个人的方案数是C(m+n-1,n-1),这个我们可以随便画上去m+n—1个求,其中选n-1个球,把整个序列划分成了n段,每一段就是每个盒子了球的个数,这样就简单证明了这个结论。
      然后,我们就可以统计出所有的方案数——∏(1~m)C(ai+n-1)(n-1)(ai是i号特产的数量)。得到这个我们也可以推出式子C(n,f)*∏(1~m)C(ai+n-f-1)(n-f-1)表示我们强制不选f个人,让他们一个都没有,也就是至少f个人一个都没有的方案数,记为f[i]。
      那么根据容斥,ans=f[0]-f[1]+f[2]-f[3]……,这样就统计出答案了。

    代码:
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define MAXN 2100
    #define mod 1000000007
    #define ll long long
    using namespace std;
    ll c[MAXN][MAXN],a[MAXN];
    ll ans=0;int n,m;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%lld",&a[i]);
        c[1][0]=c[1][1]=1;
        for(int i=2;i<=2000;i++){
            c[i][0]=1;
            for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        }
        for(int i=0,f=1;i<=n;i++,f=-f){
            int now=c[n][i];
            for(int j=1;j<=m;j++)
                now=(now*c[a[j]+n-i-1][n-i-1])%mod;
            ans=(ans+now*f)%mod;
        }
        printf("%lld",(ans+mod)%mod);
        return 0;
    }
  • 相关阅读:
    Panel内嵌入子窗体
    Dictionary绑定到ComboBox显示值,实际值
    WinFrom 窗体内嵌子窗体
    Task基础创建Task,Task传参,获取Task返回值
    Task的休眠
    ThreadLocal 弱引用和内存泄漏
    ThreadLocal核心方法源码分析
    ThreadLocal实现原理、内部结构
    ThreadLocalMap源码分析
    ribbon & feign个性化配置
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7597444.html
Copyright © 2020-2023  润新知