Loading

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

Description&Data Constraint

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

\(1\le n\le 50,1\le A_i\le 50, \sum A_i\le1500\)

Solution

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

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

有转移方程 \(f_{i,j+A_i-k-l}=f_{i-1,j}\times C_{A_i-1}^{k-1}\times C_j^l\times 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}\times\prod 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\n",ans);
	return 0;
} 
posted @ 2021-08-09 20:08  Thunder_S  阅读(80)  评论(0)    收藏  举报