[CQOI2011] 放棋子 - 计数dp
Posted mollnn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2011] 放棋子 - 计数dp相关的知识,希望对你有一定的参考价值。
在一个 (m) 行 (n) 列的棋盘里放一些彩色的棋子,使得每个格子最多放一个棋子,且不同颜色的棋子不能在同一行或者同一列,有多少种方法?
Solution
设 (f[i][j][k]) 表示用前 (k) 种颜色的棋子,占领了 (i) 行 (j) 列的方案数
设 (g[i][j][k]) 表示用任意 (k) 个同色棋子占领 (i) 行 (j) 列的方案数,则考虑总方案数 - 实际上有没有被占领的行或列的方案数,则
[g[i][j][k]=C_{ij}^k-sum_{l=1}^isum_{r=1}^j g[l][r][k]cdot C_i^l C_j^r
]
于是对 (f[i][j][k]),转移方程为
[f[i][j][k]=sum_{l=0}^{i-1} sum_{r=0}^{j-1} f[l][r][k-1]cdot g[i-l][j-r][a[k]]cdot C_{n-l}^{i-l} C_{m-r}^{j-r}
]
注意这个转移当 ((i-l)(j-r) ge a[k]) 时才成立,于是答案为
[sum_{i=1}^n sum_{j=1}^m f[i][j][c]
]
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 35;
const int mod = 1e+9+9;
int f[N][N][N],g[N][N][N*N],n,m,c,a[N],C[N*N][N*N];
signed main() {
ios::sync_with_stdio(false);
cin>>n>>m>>c;
C[0][0]=1;
for(int i=1;i<=1000;i++) {
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
}
int mx=0;
for(int i=1;i<=c;i++) cin>>a[i], mx=max(mx,a[i]);
f[0][0][0]=1;
for(signed i=1;i<=n;i++) {
for(signed j=1;j<=m;j++) {
for(signed k=1;k<=mx;k++) {
int fg=0;
for(signed t=1;t<=c;t++) if(a[t]==k) fg=1;
if(!fg) continue;
g[i][j][k]=C[i*j][k];
for(signed l=1;l<=i;l++) {
for(signed r=1;r<=j;r++) {
if(i==l && j==r) continue;
g[i][j][k]=(g[i][j][k]-g[l][r][k]*C[i][l]%mod*C[j][r]%mod+mod)%mod;
}
}
}
}
}
for(signed i=1;i<=n;i++) {
for(signed j=1;j<=m;j++) {
for(signed k=1;k<=c;k++) {
for(signed l=0;l<i;l++) {
for(signed r=0;r<j;r++) {
if((i-l)*(j-r)>=a[k])
(f[i][j][k]+=f[l][r][k-1]*g[i-l][j-r][a[k]]%mod*C[n-l][i-l]%mod*C[m-r][j-r]%mod)%=mod;
}
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) (ans+=f[i][j][c])%=mod;
cout<<ans;
}
以上是关于[CQOI2011] 放棋子 - 计数dp的主要内容,如果未能解决你的问题,请参考以下文章