博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P3158 [CQOI2011]放棋子
阅读量:4692 次
发布时间:2019-06-09

本文共 1319 字,大约阅读时间需要 4 分钟。

首先考虑到放一个棋子以后少掉的哪一行一列我们可以直接忽略,把被切开的四个部分重新拼成一个矩形

所以状态就只要考虑当前有几行几列,放了哪些棋子,考虑同一种颜色的一起放

设 $f[i][j][k]$ 表示放完前 $i$ 种颜色的棋子,剩下 $j$ 行 $k$ 列空着

那么转移直接枚举这一种颜色占了多少行列:$f[i][j][k]=\sum_{x=1}^{j+x<=n}\sum_{y=1}^{k+y<=m}f[i-1][j+x][k+y]* \binom{j+x}{x} \binom{k+y}{y} * g[x][y][a[k]] $

其中 $a[i]$ 表示颜色 $i$ 的棋子数量,$g[x][y][a[i]]$ 就表示把 $a[i]$ 个同色的棋子占 $x$ 行 $y$ 列(每一行或列都至少有一个棋子)的方案数

乘组合数是因为行列可以任选

现在问题就是如何预处理 $g$,考虑简单的容斥,总方案数减去不合法方案数

那么考虑对 $g$ 进行一波 $dp$ ,$g[i][j][k]= \binom{i*j}{k} - \sum_{x=1}^{x<=i}\sum_{y=1}^{y<=j} \binom{i}{x} \binom{j}{y} *g[x][y][k]$

即枚举多少行列没有棋子占领,组合数同样是因为行列任选

最后答案就是 $\sum_{i=0}^{n-1}\sum_{j=0}^{m-1}f[C][i][j]$ ,其中 $C$ 是颜色数

#include
#include
#include
#include
#include
using namespace std;typedef long long ll;inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f;}const int N=37,M=1007,mo=1e9+9;inline int fk(int x) { return x>=mo ? x-mo : x; }int n,m,K,tot,a[N];int C[M][M],f[N][N][N],g[N][N][M],ans;int main(){ n=read(),m=read(),K=read(); for(int i=1;i<=K;i++) a[i]=read(),tot+=a[i]; for(int i=0;i

 

 

转载于:https://www.cnblogs.com/LLTYYC/p/11550872.html

你可能感兴趣的文章