可以看做棋子放在某个位置后该种颜色就占领了那一行一列。行列间彼此没有区别。

  于是可以设f[i][j][k]表示前k种棋子占领了i行j列的方案数。转移时枚举第k种棋子占领几行几列。注意行列间是有序的,要乘上一个组合数。这里f[i][j][k]可以是在原棋盘选i行j列占领的方案数,也可以是占领i行j列棋盘的方案数,如果是第二种最后统计答案的时候还要乘上个组合数,转移略有不同但没有本质区别。我们还需要计算出k个棋子占领i行j列中的方案数才能转移。

  考虑怎么求这个东西。设其为g[i][j][k]。不妨把行列尽量往左往上移,可以发现棋子只能放置在其重合区域,也就是一个i*j的棋盘。使得这里面每行每列都有棋子就可以了。

  然而还是不太好算。考虑求存在某一行或某一列没有棋子的方案数,那么可以枚举其中有几行几列是空的转移。于是可得g[i][j][k]=C(i*j,k)-Σg[x][y][k]*C(i,x)*C(j,y) (x+y<i+j)。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f;
}
#define P 1000000009
#define N 31
#define K 11
int n,m,c,l,a[K],f[K][N][N],g[K][N][N],ans=0;
int fac[N*N],inv[N*N],C[N*N][N*N];
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
int main()
{
#ifndef ONLINE_JUDGEfreopen("bzoj3294.in","r",stdin);freopen("bzoj3294.out","w",stdout);const char LL[]="%I64d";
#elseconst char LL[]="%lld";
#endifn=read(),m=read(),c=read();for (int i=1;i<=c;i++) a[i]=read();C[1][0]=C[1][1]=1;for (int i=2;i<=n*m;i++){C[i][0]=C[i][i]=1;for (int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;}for (int k=1;k<=c;k++)for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)if (i*j>=a[k]){g[k][i][j]=C[i*j][a[k]];for (int x=1;x<=i;x++)for (int y=1;y<=j;y++)if (x<i||y<j)inc(g[k][i][j],P-1ll*C[i][x]*C[j][y]%P*g[k][x][y]%P);}f[0][0][0]=1;for (int k=1;k<=c;k++)for (int i=k;i<=n;i++)for (int j=k;j<=m;j++)if (i*j>=a[k])for (int x=1;x<=i-k+1;x++)for (int y=1;y<=j-k+1;y++)inc(f[k][i][j],1ll*f[k-1][i-x][j-y]*g[k][x][y]%P*C[n-i+x][x]%P*C[m-j+y][y]%P);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)inc(ans,f[c][i][j]);cout<<ans;return 0;
}

转载于:https://www.cnblogs.com/Gloid/p/9458177.html

BZOJ3294 CQOI2011放棋子(动态规划)相关推荐

  1. 【BZOJ 3294】 3294: [Cqoi2011]放棋子 (DP+组合数学+容斥原理)

    3294: [Cqoi2011]放棋子 Description Input 输入第一行为两个整数n, m, c,即行数.列数和棋子的颜色数.第二行包含c个正整数,即每个颜色的棋子数.所有颜色的棋子总数 ...

  2. [CQOI2011]放棋子

    C. 放棋子 题目描述 输入格式 输入第一行为两个整数n, m, c,即行数.列数和棋子的颜色数. 第二行包含c个正整数,即每个颜色的棋子数. 所有颜色的棋子总数保证不超过nm. N,M<=30 ...

  3. [CQOI2011]放棋子 题解(dp+组合数学)

    Description Input 输入第一行为两个整数n, m, c,即行数.列数和棋子的颜色数. 第二行包含c个正整数,即每个颜色的棋子数. 所有颜色的棋子总数保证不超过nm. N,M<=3 ...

  4. BZOJ4563[Haoi2016]放棋子

    题目描述 Description 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在 这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子 ...

  5. [BZOJ 4563]放棋子

    [BZOJ 4563]放棋子 题目 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子 ...

  6. 数论三之组合数学Ⅰ-Max-Min Sums,Binomial Coefficient is Fun,Strivore,Bubble Sort,放棋子,LOJ6671,Iroha and a Grid

    组合计数我最爱 Max-Min Sums description solution code Binomial Coefficient is Fun description solution code ...

  7. UVA11134传说中的车(放棋子)

    题意:       给你一个n*n的棋盘,让你在棋盘上放n个棋子,要求是所有棋子不能相互攻击(同行或者同列就会攻击),并且每个棋子都有一个限制,那就是必须在给定的矩形r[i]里,输出每个棋子的位置,s ...

  8. 蓝桥杯 第三届C/C++预赛真题(7) 放棋子(水题)

    今有 6 x 6 的棋盘格.其中某些格子已经预先放好了棋子.现在要再放上去一些,使得:每行每列都正好有3颗棋子.我们希望推算出所有可能的放法.下面的代码就实现了这个功能. 初始数组中,"1& ...

  9. 放苹果———动态规划中的划分数问题

    动态规划问题 放苹果是一道典型的DP问题,这道题采用递归+分治+DP的方式解决. 题目描述 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和 ...

最新文章

  1. AR模型、MA(Moving Average)模型、ARMA模型、时间序列的定阶、ARIMA、SARIMAX
  2. SQL函数设计——临时表的使用
  3. Mysql删除语句优化_MySQL性能优化之常用SQL语句优化
  4. 从比特币脚本引擎到以太坊虚拟机
  5. 敏捷嘉年华——敏捷之旅2012(上海站)
  6. 【网址收藏】rancher镜像源仓库
  7. 中国科学院计算机专业职称,2018年春季工程技术系列专业技术资格职称评审结束...
  8. React中自定义方法
  9. Git 安装及 idea 配置 Git
  10. 数据结构与算法-列表相关时间复杂度
  11. 洛谷P2568 GCD(莫比乌斯反演)
  12. php 去除div标签,JavaScript_清除div下面的所有标签的方法,复制代码 代码如下: div id=s - phpStudy...
  13. android9.0 uri,Android9.0源码学习 - Launcher Activity(一)
  14. BeyondCompare 源代码比对解决方案
  15. 宏碁笔记本一键重装win7系统教程
  16. 分享淘宝的IP地址库查询接口
  17. 图像分割-分水岭算法和GrabCut 算法
  18. C++ 中 substr 函数的用法
  19. 西电计算机通信原理,西电通信原理大作业
  20. [Java 一道简单的排序题]

热门文章

  1. TCP/IP学习笔记(三)TCP流量控制以及滑动窗口
  2. linux网络编程-----非阻塞connect
  3. 获取PE文件的区段表
  4. zzuli 2269:minval
  5. mysql实体_mysql实体关系
  6. Linux 创建交换(swap)分区
  7. C 中 static 的常见作用
  8. C++---类成员变量定义为引用
  9. java定义一个getsize方法,long getSize()
  10. linux多线程信号总结