4254. 【五校联考7day2】集体照

Description&Data Constraint

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

(1le nle 50,1le A_ile 50, sum A_ile1500)

Solution

(f_{i,j}) 表示前 (i) 个班有 (j) 个位置相邻两个是同班的。统计 (A_i) 的前缀和 (sum_i)

由于同班的每个人交换位置是不同的方案,我们可以最后乘上 (prod A_i)

有转移方程 (f_{i,j+A_i-k-l}=f_{i-1,j} imes C_{A_i-1}^{k-1} imes C_j^l imes C_{sum_{i-1}+1-j}^{k-l})​。枚举 (k)(l)。其中 (k) 表示把 (A_i) 分成 (k) 组,(l) 表示这 (l) 组插入在 (j) 中的 (l) 个位置。

  • (C^{k-1}_{a_{i-1}})​ 表示把 (A_i) 分成 (k)​ 组的方案数(插板)
  • (C_j^l) 表示 (j)(l) 的方案数。
  • (C_{sum_{i-1}+1-j}^{k-l}) 表示在其他位置插入剩下的 (k-l) 组的方案数。

最后答案就是 (f_{n,0} imesprod A_i!)

预处理组合数和阶乘。

Code

#include<cstdio>
#include<algorithm>
#define mod 1000000007
#define ll long long
#define N 55
#define A 1505
using namespace std;
ll n,ans,a[N],jc[A],c[A][A],f[N][A],sum[N];
int main()
{
	freopen("photo.in","r",stdin);
	freopen("photo.out","w",stdout);
	jc[0]=c[0][0]=1;
	for (int i=1;i<=A;++i)
		jc[i]=jc[i-1]*i%mod;
	for (int i=1;i<=A;++i)
		c[i][0]=c[i][i]=1;
	for (int i=2;i<=A;++i)
		for (int j=1;j<i;++j)
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
	scanf("%lld",&n);
	for (int i=1;i<=n;++i)
	{
		scanf("%lld",&a[i]);
		sum[i]=sum[i-1]+a[i];
	}
	f[1][sum[1]-1]=1;
	for (int i=2;i<=n;++i)
		for (int j=0;j<=sum[i-1];++j)
			if (f[i-1][j])
				for (int k=1;k<=a[i];++k)
					for (int l=0;l<=min(k,j);++l)
						f[i][j+a[i]-k-l]=(f[i][j+a[i]-k-l]+f[i-1][j]*c[a[i]-1][k-1]%mod*c[j][l]%mod*c[sum[i-1]+1-j][k-l]%mod)%mod;
	ans=f[n][0];
	for (int i=1;i<=n;++i)
		ans=ans*jc[a[i]]%mod;
	printf("%lld
",ans);
	return 0;
} 
原文地址:https://www.cnblogs.com/Livingston/p/15120362.html