bzoj3294: [Cqoi2011]放棋子
Posted akcqhzdy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3294: [Cqoi2011]放棋子相关的知识,希望对你有一定的参考价值。
明显的,行列的顺序是没有关系的
我们可以考虑用几个块+组合顺序把答案拼出来
十种颜色难以状压,但是我们可以对于每种颜色,把它覆盖i行j列的方案数给算出来
LL g[maxC][maxl][maxl];//用cn[i]个棋子占i行j列并且一定占满 ------> 的方案数
LL f[maxC][maxl][maxl];//前c种棋子占i行j列 -----> 的方案数
这样上一个二维的背包,每次弄一个组合数算一下行插在那,列插在那就完了
现在讨论一下g怎么求,我们需要容斥一下
可以用总的方案数-有某些行或某些列没被覆盖的方案数
总的:有i*j个坑可以填
再减去u<=i,v<=j 却也用够了cn[i]的方案,它也有多种组合方式
具体见代码
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int maxl=33; const int maxC=13,sumC=1100; const LL mod=1e9+9; LL C[maxl*maxl][maxl*maxl]; void initC() { C[0][0]=1; for(int i=1;i<maxl*maxl;i++) { C[i][0]=1; for(int j=1;j<maxl*maxl;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } } //~~~~~~~~~~~init~~~~~~~~~~~~~~~~ LL g[maxC][maxl][maxl];//用cn[i]个棋子占i行j列并且一定占满 ------> 的方案数 LL f[maxC][maxl][maxl];//前c种棋子占i行j列 -----> 的方案数 int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); initC(); int n,m,CC; scanf("%d%d%d",&n,&m,&CC); for(int t=1;t<=CC;t++) { int c; scanf("%d",&c); for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) { g[t][i][j]=C[i*j][c]; for(int u=0;u<=i;u++) for(int v=0;v<=j;v++) { if(u==i&&v==j)continue; g[t][i][j]=(g[t][i][j]-g[t][u][v]*C[i][u]*C[j][v])%mod; } g[t][i][j]=(g[t][i][j]+mod)%mod; } } f[0][0][0]=1; for(int t=1;t<=CC;t++) for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) for(int u=0;u+i<=n;u++) for(int v=0;v+j<=m;v++) f[t][i+u][j+v]+=f[t-1][i][j]*g[t][u][v]%mod*C[n-i][u]%mod*C[m-j][v]%mod; LL ans=0; for(int i=0;i<=n;i++) for(int j=0;j<=m;j++) ans=(ans+f[CC][i][j])%mod; printf("%lld ",ans); return 0; }
LL g[maxC][maxl][maxl];//用cn[i]个棋子占i行j列并且一定占满 ------> 的方案数 LL f[maxC][maxl][maxl];//前c种棋子占i行j列 -----> 的方案数
以上是关于bzoj3294: [Cqoi2011]放棋子的主要内容,如果未能解决你的问题,请参考以下文章