[计数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 }

原文地址:https://www.cnblogs.com/Comfortable/p/10339519.html

时间: 2024-08-30 17:18:40

[计数dp][数学] Jzoj P4254 集体照的相关文章

[DP][数学]JZOJ 3318 Brunhilda的生日

Description 除去对铁质盔甲强烈的热爱,Brunhilda是一个正常的7岁女孩.近期,她正在策划一个完美的生日派对.她发明了如下的一个游戏:所有的孩子在一个数k被宣读之前不停地跑来跑去.当这个数字k宣读后,所有的孩子将形成人数恰好为k的若干群体,且保证剩余的孩子数目小于k.最后,这不足k个的孩子将从游戏中被淘汰.紧接着,比赛将继续进行,并公布一个新的数字k.游戏将在所有的孩子都被淘汰后结束. Brunhilda请她的父亲Wotan在游戏中来宣读数字.Wotan不喜欢这个游戏,当然也不希

ACM/ICPC算法训练 之 数学很重要-浅谈“排列计数” (DP题-POJ1037)

这一题是最近在看Coursera的<算法与设计>的公开课时看到的一道较难的DP例题,之所以写下来,一方面是因为DP的状态我想了很久才想明白,所以借此记录,另一方面是看到这一题有运用到 排列计数 的方法,虽然排列计数的思路简单,但却是算法中一个数学优化的点睛之笔. Poj1037  A decorative fence 题意:有K组数据(1~100),每组数据给出总木棒数N(1~20)和一个排列数C(64位整型范围内),N个木棒长度各异,按照以下条件排列,并将所有可能结果进行字典序排序 1.每一

HDU4815/计数DP

题目链接[http://acm.hdu.edu.cn/showproblem.php?pid=4815] 简单说一下题意: 有n道题,每到题答对得分为a[ i ],假如A不输给B的最小概率是P,那么A最少要得到多少分. 解题过程: 假设有n道题,每个题有两个状态,胜或者败,假设达到某个分数m有k(计数DP)种方式,那么最后是这个分数的概率是k/pow(2,n).那么A不输给B的概率就是小于等于m的分数的概率和. #include<bits/stdc++.h> const int maxn =

hdu-5621 KK&#39;s Point(dp+数学)

题目链接: KK's Point Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description Our lovely KK has a difficult mathematical problem:He points N(2≤N≤10^5) points on a circle,there are all different.Now he's goi

[sdut]2879计数dp……或者递推

第五届省赛C:colourful cupcakes N=60. 天真如我,居然在考虑搜索的算法/(ㄒoㄒ)/~~三叉树……3^60=10^24+……不计算考虑复杂度都是耍流氓>_< 再算了一下,感觉O(N^4)可以试试,60^4=10^8+……但是毕竟最差的情况嘛>_<,再看一下题解果然是4重循环的……计数……dp……(想到之前坚信的搜索不禁(*/ω\*)) 中间看到了一个三次动规六个方程的算法. 做麻烦了. 学长思路好快. #include<iostream> #in

HDU4901 The Romantic Hero 计数DP

2014多校4的1005 题目:http://acm.hdu.edu.cn/showproblem.php?pid=4901 The Romantic Hero Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 393    Accepted Submission(s): 150 Problem Description There i

[计数dp] ural 1114. Boxes

题目链接: http://acm.timus.ru/problem.aspx?space=1&num=1114 1114. Boxes Time limit: 0.6 second Memory limit: 64 MB N boxes are lined up in a sequence (1 ≤ N ≤ 20). You have A red balls and B blue balls (0 ≤ A ≤ 15, 0 ≤ B ≤ 15). The red balls (and the blu

CodeForces 176B Word Cut (计数DP)

Word Cut Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 176B Description Let's consider one interesting word game. In this game you should transform one word into another through specia

洛谷P1061 Jam的计数法 数学

洛谷P1061 Jam的计数法 数学 已知一个字符串 其 均有 s--t构成 且字符串要求 s[ i ]<s[ j ] i < j 已知一个字符串 求按字典序排列 的后5个字符串 1. 对于一个字符串已知,我们如何求他的下一个字符串呢? 我们可以从低位枚举到高位,找到第一个可以增长的数,然后增长2.同时把自己后面的串改为字典序最小,即这一位为上一位 + 1 这样字典序就最小了 1 #include <cstdio> 2 #include <cmath> 3 #inclu