JZOJ 4872.集体照

( ext{Problem})

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

( ext{Solution})

考虑 (dp),按班级做,插入人
(f_{i,j}) 表示做到第 (i) 个班,已经出现 (j) 对相邻
那么转移就是当前班分 (k) 组,选 (t) 组插到 (j) 个空中,使他们分离

( ext{Code})

#include<cstdio>
#include<algorithm>
#define LL long long 
#define re register
using namespace std;

const LL P = 1e9 + 7;
int n, a[55], sum[55];
LL fac[1505], C[1505][1505], f[55][1505];

inline void ADD(LL &x, LL y)
{
	x += y;
	if (x > P) x -= P;
}

int main() 
{
	freopen("photo.in", "r", stdin);
	freopen("photo.out", "w", stdout);
	scanf("%d", &n);
	for(re int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i];
	fac[0] = 1;
	for(re int i = 1; i <= sum[n]; i++) fac[i] = fac[i - 1] * i % P;
	for(re int i = 0; i <= sum[n]; i++) C[i][0] = 1;
	for(re int i = 1; i <= sum[n]; i++)
		for(re int j = 1; j <= i; j++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % P;
	f[1][a[1] - 1] = 1;
	for(re int i = 2; i <= n; i++)
		for(re int j = 0; j < sum[i - 1]; j++)
			for(re int k = 1; k <= a[i]; k++) 
				for(re int t = 0; t <= k; t++)
					ADD(f[i][j + a[i] - k - t], f[i - 1][j] * C[a[i] - 1][k - 1] % P * C[j][t] % P * C[sum[i - 1] + 1 - j][k - t] % P);
	LL ans = f[n][0];
	for(re int i = 1; i <= n; i++) ans = ans * fac[a[i]] % P;
	printf("%lld
", ans);
}
原文地址:https://www.cnblogs.com/leiyuanze/p/15127488.html