洛谷P3158 [CQOI2011]放棋子

题目描述
题解

考虑 dp \text{dp} dp f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 表示用前 k k k 种棋子占领了 i i i j j j 列的方案数

考虑 f f f 的转移: f [ i ] [ j ] [ k ] = ∑ l = 0 i − 1 ∑ r = 0 j − 1 f [ l ] [ r ] [ k − 1 ] × ( i − l n − l ) × ( j − r m − r ) × g [ i − l ] [ j − l ] [ a [ k ] ] f[i][j][k]=\sum_{l=0}^{i-1}\sum_{r=0}^{j-1}f[l][r][k-1] \times (_{i-l}^{n-l}) \times (_{j-r}^{m-r}) \times g[i-l][j-l][a[k]] f[i][j][k]=l=0i1r=0j1f[l][r][k1]×(ilnl)×(jrmr)×g[il][jl][a[k]] ,其中 g [ i ] [ j ] [ k ] g[i][j][k] g[i][j][k] 表示用 k k k 个同种颜色的棋子占领 i i i j j j 列的方案数

考虑 g g g 的转移,发现我们可以容斥,即用总方案数-有些行列没有被占领的方案数,故 g [ i ] [ j ] [ k ] = ( k i ∗ j ) − ∑ l = 1 i ∑ r = 1 j [ l < i   ∣ ∣   r < j ] × g [ l ] [ r ] [ k ] × ( l i ) × ( r j ) g[i][j][k]=(_k^{i*j})-\sum_{l=1}^{i}\sum_{r=1}^{j} [l<i\ ||\ r<j] \times g[l][r][k] \times (_l^i) \times (_r^j) g[i][j][k]=(kij)l=1ir=1j[l<i  r<j]×g[l][r][k]×(li)×(rj)

答案即为: ∑ i = 1 n ∑ j = 1 m f [ i ] [ j ] [ c ] \sum_{i=1}^n\sum_{j=1}^mf[i][j][c] i=1nj=1mf[i][j][c] ,效率: O ( n 2 m 2 c ) O(n^2m^2c) O(n2m2c)

代码
#include <cstdio>
const int P=1e9+9;
int n,m,c,a[15],f[35][35][15],g[35][35][15],jc[905],ny[905],A;
int C(int x,int y){
	if (x<y) return 0;
	return 1ll*jc[x]*ny[y]%P*ny[x-y]%P;
}
int main(){
	scanf("%d%d%d",&n,&m,&c);jc[0]=ny[n*m]=f[0][0][0]=1;
	for (int i=1;i<=n*m;i++) jc[i]=1ll*i*jc[i-1]%P;
	for (int y=P-2,x=jc[n*m];y;y>>=1,x=1ll*x*x%P)
		if (y&1) ny[n*m]=1ll*ny[n*m]*x%P;
	for (int i=n*m;i;i--) ny[i-1]=1ll*i*ny[i]%P;
	for (int i=1;i<=c;i++) scanf("%d",&a[i]);
	for (int k=1;k<=c;k++){
		for (int i=1;i<=n;i++) for (int j=1;j<=m;j++){
			g[i][j][k]=C(i*j,a[k]);
			for (int l=1;l<=i;l++) for (int r=1;r<=j;r++) if (l<i || r<j)
				(g[i][j][k]-=1ll*g[l][r][k]*C(i,l)%P*C(j,r)%P)%=P;
		}
		for (int i=1;i<=n;i++) for (int j=1;j<=m;j++)
			for (int l=0;l<i;l++) for (int r=0;r<j;r++)
				(f[i][j][k]+=1ll*f[l][r][k-1]*C(n-l,i-l)%P*C(m-r,j-r)%P*g[i-l][j-r][k]%P)%=P;
	}
	for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) (A+=f[i][j][c])%=P;
	return printf("%d\n",(A+P)%P),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值