zoukankan      html  css  js  c++  java
  • [计数dp][数学] Jzoj P4254 集体照

    Description

         一年一度的高考结束了,我校要拍集体照。本届毕业生共分n个班,每个班的人数为Ai。这次拍集体照的要求非常奇怪:所有学生站一排,且相邻两个学生不能同班。现在,安排这次集体照的老师找到了你,想问问你一共有多少种方案。方案数可能很大,最终结果对1,000,000,007取模。
     

    Input

    输入文件名为photo.in。
    第一行为为一个整数n。
    第二行为n个正整数,分别为每个班的人数。

    Output

    输出文件photo.out,共1行,为总方案数。
     

    Sample Input

    输入1:
    2
    1 2
    输入2:
    2 
    1 3
    输入3:
    3 
    1 2 3
     

    Sample Output

    输出1:
    2
    输出2:
    0
    输出3:
    120
     

    Data Constraint

    对于30%,Sigma(Ai) <=10
    对于另外10%,n=2
    对于另外20%,n=3
    对于100%,1<=n<=50,1<=Ai<=50, Sigma(Ai)<=1500

    题解

    • 题目大意:问有n个班,每个班有a[i]个人,问相邻两个人都不同班的方案数
    • n<=50,∑Ai<=1500,极其优秀的范围,考虑一下dp,设f[i][j]表示做到前i个班,有j个相邻为同班为位置的方案数
    • 首先,根据样例我们可以得出,每个班的每个人互换位置也算一种方案数,那么我们先考虑每个班里的人都是火柴人
    • 那么这个dp的状态转移方程为
    • 就是将A[i]分成k组,将t组插入分配到之前j个相邻的位置中,就是将t组分配插入到j个位置的方案数,就是将A[i]分成k组的方案数(就是挡板问题),就是将剩下的k-t组分配到剩下的原来合法的位置中的方案数
    • 然后怎么求呢,显然就可以预处理出组合数(杨辉三角)和阶乘(等下就知道了),答案就是F[n][0]
    • 那么我们返回来求每个班内不同人的分配,就是排列问题嘛,就是a[i]!
    • 所以最后的答案就为

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #define ll long long
     5 #define N 60
     6 #define M 1510
     7 #define mo 1000000007
     8 using namespace std;
     9 int n;
    10 ll a[N],sum[N],f[N][M],jc[M],c[M][M],ans;
    11 int main()
    12 {
    13     freopen("photo.in","r",stdin),freopen("photo.out","w",stdout),scanf("%d",&n);
    14     for (int i=1;i<=n;i++) scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
    15     jc[0]=c[0][0]=1; for (int i=1;i<=1500;i++) jc[i]=jc[i-1]*i%mo;
    16     for (int i=1;i<=1500;i++)
    17     {
    18         c[i][0]=c[i][i]=1;
    19         for (int j=1;j<=i-1;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
    20     }
    21     f[1][sum[1]-1]=1;
    22     for (int i=2;i<=n;i++)
    23         for (int j=0;j<=sum[i-1];j++)
    24             if (f[i-1][j])
    25                 for (int k=1;k<=a[i];k++)
    26                     for (int p=0;p<=min(k,j);p++)
    27                         (f[i][j-p+a[i]-k]+=f[i-1][j]*c[j][p]%mo*c[a[i]-1][k-1]%mo*c[sum[i-1]+1-j][k-p]%mo)%=mo;
    28     ans=f[n][0];
    29     for (int i=1;i<=n;i++) ans=ans*jc[a[i]]%mo;
    30     printf("%lld",ans);
    31 }
  • 相关阅读:
    Linux对文件的权限管理
    在Eclipse中安装TestNG
    JUnit 4 与 TestNG 对比
    postman之HTTP请求
    Fiddler抓包后保存为JMX(jmeter脚本,不限jmeter使用版本)
    JMeter使用之BlazeMeter的安装及初步使用
    Postman的第一个案例演示
    Postman的安装及注意事项
    SVN学习记录
    TestNG中如何执行测试
  • 原文地址:https://www.cnblogs.com/Comfortable/p/10339519.html
Copyright © 2011-2022 走看看