比较头疼的计数题.
我们发现,放置一个棋子会使得该棋子所在的1个行和1个列都只能放同种棋子.
定义状态 $f_{i,j,k}$ 表示目前已使用了 $i$ 个行,$j$ 个列,并放置了前 $k$ 种棋子的方案数.
假设当前枚举到的是第 $k$ 个棋子,该种棋子有 $num_{k}$ 个.
枚举 $d1,d2$ 表示安排这 $num_{k}$ 个棋子需要用 $d1$ 个行,$d2$ 个列.
可以将 $d1$ 个行和 $d2$ 个列并到一起,这就构成了一个 $d1\times d2$ 的矩形.
在这个矩形中要选取 $num_{k}$ 个棋子,且 $d1$ 个行和 $d2$ 个列中每一个行和列都至少要有一个棋子.
我们像要求这个东西的方案数.
分析到这步就卡住了,我想的递推式不够优秀.
同届神犇 $JZYshurak$ 给了一个容斥的解决方案 :
令 $g_{i,j,k}$ 表示在 $i\times j$ 的矩阵中安放第 $k$ 种颜色,且每个行和列都有棋子的方案数.
正着求不好求,考虑容斥:$C_{i\times j}^{num_{k}}-\sum_{x=1}^{i}\sum_{y=1}^{j}C_{i}^{x}\times C_{j}^{y}\times g_{x,y,k}$.
这个容斥的意义: 总的方案 - 不合法方案.
那么不合法方案就是 $num_{k}$ 个棋子覆盖的行和列都小于 $i$ 与 $j$ 的方案总和,还要乘一下组合数,因为矩形是我们拼凑的,实际中这个矩形的行和列都是散落的.
综上,$f_{i,j,k}=f_{i-d1,j-d2,k-1}\times C_{n-i+d1}^{d1}\times C_{m-j+d2}^{d2}\times g_{d1,d2,k}$.
时间复杂度为 $O(cn^2m^2)$

#include <cstdio>
#include <algorithm>
#define N 33
#define mod 1000000009
#define ll long long
#define setIO(s) freopen(s".in" , "r" , stdin)
using namespace std;
int num[N], n , m, c;
ll f[N][N][13], fac[1000], inv[1000], G[N][N][10];
inline ll qpow(ll base, ll k)
{
ll tmp = 1ll;
for( ; k ; base = (base * base) % mod , k >>= 1) if(k & 1) tmp = (tmp * base) % mod;
return tmp;
}
inline ll C(int a, int b)
{
return fac[a] * inv[b] % mod * inv[a - b] % mod;
}
inline void init()
{
int i , j;
f[0][0][0] = 1ll;
fac[0] = inv[0] = 1;
for(i = 1; i <= n * m ; ++ i)
{
fac[i] = (fac[i - 1] * i) % mod ;
inv[i] = qpow(fac[i] , mod - 2);
}
}
inline void Getg()
{
int i , j , k , x, y;
for(k = 1; k <= c; ++ k)
{
for(i = 1; i <= n ; ++ i)
{
for(j = 1; j <= m ; ++ j)
{
if(i * j < num[k]) continue;
G[i][j][k] = C(i * j , num[k]);
for(x = 1; x <= i ; ++ x)
{
for(y = 1; y <= j ; ++ y)
{
if(x * y < num[k] || (x == i && y == j)) continue;
G[i][j][k] = (G[i][j][k] - (C(i, x) * C(j, y) % mod * G[x][y][k] % mod) + mod) % mod;
}
}
}
}
}
}
inline int up(int a, int b)
{
if(a % b == 0) return a / b;
else return (a / b) + 1;
}
int main()
{
int i , j , k;
ll re = 0;
scanf("%d%d%d",&n , &m , &c);
for(i = 1; i <= c ; ++ i) scanf("%d", &num[i]);
init(), Getg();
for(k = 1; k <= c ; ++ k)
{
for(i = 1; i <= n ; ++ i)
for(j = 1; j <= m ; ++ j)
{
int d1, d2;
for(d1 = 1; d1 <= num[k]; ++ d1)
{
if(d1 > i) break;
for(d2 = up(num[k], d1); d2 <= num[k]; ++ d2)
{
if(d2 > j) break;
ll t = f[i - d1][j - d2][k - 1] * C(n - i + d1, d1) % mod * C(m - j + d2, d2) % mod * G[d1][d2][k] % mod;
f[i][j][k] = (f[i][j][k] + t) % mod;
}
}
if(k == c)
{
re = (re + f[i][j][k]) % mod;
}
}
}
printf("%lld\n", re);
return 0;
}

  

BZOJ 3294: [Cqoi2011]放棋子 计数 + 容斥 + 组合的更多相关文章

  1. BZOJ 3294: [Cqoi2011]放棋子(计数dp)

    传送门 解题思路 设\(f[i][j][k]\)表示前\(k\)个颜色的棋子占领了\(i\)行\(j\)列的方案数,那么转移时可以枚举上一个颜色时占领的位置,\(f[i][j][k]=\sum\lim ...

  2. BZOJ 3294: [Cqoi2011]放棋子

    3294: [Cqoi2011]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 628  Solved: 238[Submit][Status] ...

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

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

  4. bzoj2839: 集合计数 容斥+组合

    2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 523  Solved: 287[Submit][Status][Discuss] ...

  5. BZOJ 3456 NTT图的计数 容斥

    思路: RT 懒得写了 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm&g ...

  6. bzoj3294[Cqoi2011]放棋子 dp+组合+容斥

    3294: [Cqoi2011]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 755  Solved: 294[Submit][Status] ...

  7. bzoj千题计划261:bzoj3294: [Cqoi2011]放棋子

    http://www.lydsy.com/JudgeOnline/problem.php?id=3294 如果一个颜色的棋子放在了第i行第j列,那这种颜色就会占据第i行第j列,其他颜色不能往这儿放 设 ...

  8. bzoj 2839 集合计数 容斥\广义容斥

    LINK:集合计数 容斥简单题 却引出我对广义容斥的深思. 一直以来我都不理解广义容斥是为什么 在什么情况下使用. 给一张图: 这张图想要表达的意思就是这道题目的意思 而求的东西也和题目一致. 特点: ...

  9. [洛谷P3158] [CQOI2011]放棋子

    洛谷题目链接:[CQOI2011]放棋子 题目描述 在一个m行n列的棋盘里放一些彩色的棋子,使得每个格子最多放一个棋子,且不同 颜色的棋子不能在同一行或者同一列.有多少祌方法?例如,n=m=3,有两个 ...

随机推荐

  1. CF1187E Tree Painting【换根dp】

    题目传送门 题意 一棵$N$个节点的树,初始时所有的节点都是白色,第一次可以选择任意一个把它涂成黑色.接下来,只能把与黑色节点原来相连的白色节点涂成黑色(涂成黑色的点视为被删去,与其它节点不相连).每 ...

  2. 第八周课程总结&实验报告

    实验六 Java异常 •实验目的 •理解异常的基本概念: •掌握异常处理方法及熟悉常见异常的捕获方法. • 实验要求 •练习捕获异常.声明异常.抛出异常的方法.熟悉try和catch子句的使用. •掌 ...

  3. Shell 变量详解教程之位置变量与预定义变量

    Shell 变量分为3部分,分别是用户自定义变量.位置变量和预定义变量. 一.   自定义变量 那么,什么是变量呢?简单的说,就是让某一个特定字符串代表不固定的内容,用户定义的变量是最普通的Shell ...

  4. Excel透视表进阶之计算字段、计算项、切片器、页面布局

    计算字段 在透视表的字段列表中通过函数.公式等方式构建一个新的字段 又称虚拟字段,因为计算字段不会出现在数据源中,对于普通字段的操作,都可以对计算字段进行操作 计算字段只能出现在值区域,不能出现在筛选 ...

  5. 【洛谷p1051】谁拿了最多奖学金

    谁拿了最多奖学金[题目链接] 这道题早就想做它啦. 咱也不知道为啥,咱就是看这道题特别顺眼呢qwq: MY SOLUTION: 其实这道题很简单,开一个结构体记录各项信息,然后根据条件计算出这个人获得 ...

  6. 2017.9.23 C组比赛总结

    今天又回到了C组,感觉爽歪歪~分数终于是个三位数了,yes! 第一题,赛车.水!只用一个贪心就可以AC了. first,以速度为关键字小到大qsort一下... scond,枚举每一个赛车,看看它可以 ...

  7. 教你搭建基于typescript的vue项目

    自尤大去年9月推出vue对typescript的支持后,一直想开箱尝试,对于前端sr来说,vue的顺滑加上ts的面向对象,想着就非常美好~ 终于在两个月前,找到了个机会尝试了一把vue+ts的组合. ...

  8. random 方法 生成随机数

    Math.random() 生成 大于等于0.0 且小于 1.0 的double 型随机数 ( 0.0 <= Math.random() < 1.0 ) 可以使用它便携简单了表达式,生成任 ...

  9. Java面试总结 -2018(补录)

    参考详见:https://blog.csdn.net/jackfrued/article/details/44921941 https://blog.csdn.net/jackfrued/articl ...

  10. C++ ->error LNK1123

    终极解决方案:VS2010在经历一些更新后,建立Win32 Console Project时会出“error LNK1123” 错误,解决方案为将 项目|项目属性|配置属性|清单工具|输入和输出|嵌入 ...