• bzoj4710 [Jsoi2011]分特产


    Description

    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

    正解:组合数学+容斥原理。

    因为要保证每个人都有特产,所以很不好处理。我们可以考虑容斥,即求出所有情况,再减去至少一个人没有特产的情况,再加上至少两个人没有特产的情况。。。以此类推

    设$n$个人的所有情况为$f[n]$。显然我们可以分开考虑每一种特产,对于每一种特产我们就是要把它丢到$n$个人里,且可以有人没有特产,那么答案就是可重组合$inom{n+r-1}{n-1}$,把所有的特产的方案乘起来,得到$f[n]$的值。

    然后容斥,$Ans=inom{n}{0}f[n]-inom{n}{1}f[n-1]+inom{n}{2}f[n-2]-...$,于是这道题就做完了。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define rhl (1000000007)
     6 #define N (3010)
     7 
     8 using namespace std;
     9 
    10 int fac[N],ifac[N],inv[N],a[N],n,m,ans;
    11 
    12 il int gi(){
    13   RG int x=0,q=1; RG char ch=getchar();
    14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    15   if (ch=='-') q=-1,ch=getchar();
    16   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    17   return q*x;
    18 }
    19 
    20 il int C(RG int n,RG int m){
    21   if (n<m) return 0;
    22   return 1LL*fac[n]*ifac[m]%rhl*ifac[n-m]%rhl;
    23 }
    24 
    25 int main(){
    26 #ifndef ONLINE_JUDGE
    27   freopen("product.in","r",stdin);
    28   freopen("product.out","w",stdout);
    29 #endif
    30   n=gi(),m=gi();
    31   for (RG int i=1;i<=m;++i) a[i]=gi();
    32   fac[0]=fac[1]=ifac[0]=ifac[1]=inv[1]=1;
    33   for (RG int i=2;i<=3000;++i){
    34     fac[i]=1LL*fac[i-1]*i%rhl;
    35     inv[i]=1LL*(rhl-rhl/i)*inv[rhl%i]%rhl;
    36     ifac[i]=1LL*ifac[i-1]*inv[i]%rhl;
    37   }
    38   for (RG int i=1,res;i<=n;++i){
    39     res=1;
    40     for (RG int j=1;j<=m;++j)
    41       res=1LL*res*C(i+a[j]-1,i-1)%rhl;
    42     if ((n-i)&1){
    43       ans=(ans-1LL*res*C(n,n-i))%rhl;
    44       if (ans<0) ans+=rhl;
    45     } else ans=(ans+1LL*res*C(n,n-i))%rhl;
    46   }
    47   cout<<ans; return 0;
    48 }
  • 相关阅读:
    2020春,不一样的学期不一样的软工实践
    尘埃落下,我抓住透明的阳光,温暖留在掌心
    敏捷软工
    《构建之法》& CI/CD调研
    2021年-软件工程-热身阅读作业
    从学生到科技工作者
    希望我能帮到你:给同学们软件开发的建议
    CC2020 分享信息
    【计算机教育】看《计算机科学导论》,发展计算思维能力
    【计算机教育】创新工程实践课程的反馈
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7604114.html
Copyright © 2020-2023  润新知