CF140E

\(m\)种颜色,\(n\)层,给每层\(l_i\)个位置涂色,要求相邻位置颜色不同,相邻层数颜色集合也不能相同,求方案数

考虑在一行内彩球的方案数,\(g[i][j]\)表示一共\(i\)个球串成一行,共用\(j\)种颜色的方案数

类似最小表示法简化计数,强制令其有序,实际方案数为\(g[i][j]*j!\)

若前\(i-1\)个球使用了\(j-1\)种颜色,则第\(i\)个球必然使用了第\(j\)种颜色;若前\(i-1\)个球已使用了\(j\)种颜色,则第\(i\)个球使用的颜色必须与第\(i-1\)个球不同,所以有\((j-1)\)种方案

\(g[i][j]=g[i-1][j-1]+(j-1)g[i-1][j]\)

考虑行与行的影响

\(f[i][j]\)表示前\(i\)层恰用了\(j\)种颜色

若不考虑两层之间颜色集合需不同

\(f[i][j]=A_m^j*g[l[i]][j]*\sum f[i-1][k]\)

减去不合法

\(f[i][j]=A_m^j*g[l[i]][j]*\sum f[i-1][k]-f[i-1][j]*g[l[i]][j]*j!\)

ll n,m,mod,maxx,l[2000005],A[M],fac[M],f[5005][5005],g[2][5010];
int main(){
	scanf("%lld%lld%lld",&n,&m,&mod); fac[0] = A[0] = f[0][0] = 1;
	for(int i = 1;i <= n;++i) l[i] = read(),maxx = max(maxx,l[i]);
	for(int i = 1;i <= maxx;++i) A[i] = A[i-1] * (m-i+1) % mod;
	for(int i = 1;i <= maxx;++i) fac[i] = fac[i-1] * i % mod;
	for(int i = 1;i <= maxx;++i)
		for(int j = 1;j <= i && j <= m;++j)
			f[i][j] = (f[i-1][j-1] + f[i-1][j]*(j-1)) % mod;
	ll ans = 1,sum = 0;
	for(int i = 1;i <= n;++i){
		for(int j = 1;j <= l[i];++j){
			ll tmp = (A[j]*ans - g[i&1^1][j]*fac[j]) % mod;
			g[i & 1][j] = f[l[i]][j] * tmp % mod;
			sum += g[i & 1][j];
		}
		ans = (sum % mod + mod) % mod; sum = 0;
		memset(g[i&1^1],0,sizeof(g[0]));
	}
	printf("%lld",ans);
}
posted @ 2020-10-17 10:39  INFP  阅读(84)  评论(0编辑  收藏  举报