[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}^i\sum_{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;
}

原文地址:https://www.cnblogs.com/mollnn/p/12643871.html

时间: 2024-10-22 02:41:38

[CQOI2011] 放棋子 - 计数dp的相关文章

P3158 [CQOI2011]放棋子(dp+组合数)

P3158 [CQOI2011]放棋子 放棋子的顺序和方案数无关,所以可以从按颜色递推 设$f[u][p][k]$为放到第$u$种颜色,所剩空间$p*k$的方案数 $g[u][i][j]$表示第$u$种颜色占据$i*j$空间的方案数,可以预处理 $g[u][i][j]=\binom{i*j}{c[u]}-\sum_{p=1}^{i}\sum_{k=1}^{j}g[u][p][k]*\binom{i}{i-p}*\binom{j}{j-k}*[p<i||j<k]$ $f[u][p][k]=\su

BZOJ 3294: [Cqoi2011]放棋子

3294: [Cqoi2011]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 628  Solved: 238[Submit][Status][Discuss] Description Input 输入第一行为两个整数n, m, c,即行数.列数和棋子的颜色数.第二行包含c个正整数,即每个颜色的棋子数.所有颜色的棋子总数保证不超过nm. Output 输出仅一行,即方案总数除以 1,000,000,009的余数. Sample Input

[题解] [CQOI2011] 放棋子

题面 题解 为了练习计数而做 注意到一种颜色占据的行, 列其他的颜色不能放 又考虑到我们并不需要知道哪些行哪些列选了, 只需要知道还有几行几列没选即可 于是有 \(f[i][j][k]\) 代表前 \(i\) 种颜色选完之后, 还有 \(j\) 行没选, \(k\) 列没选的方案数 \(g[i][j][k]\) 代表, \(i\) 个棋子, 放在 \(j\) 行 \(k\) 列中并且没有空行空列的方案数 \(cnt_i\) 代表颜色为 \(i\) 的棋子有几个 有 \[ \displaystyl

[CQOI2011]放棋子

想到了50%吧算是. f[i][j][k]表示,前i种,占了j行k列.方案数. 发现,转移要处理:"用c个棋子,占据n行m列"的方案数. 设g[i][j][k]表示,i行j列用k个棋子占的方案数.直接处理复杂度爆炸. 然后我就mengbier了. 考虑大力容斥: 也即,总方案数-不合法方案数(不能覆盖完全) g[i][j][k]=C(i*j,k)-∑l∑r:g[l][r][k]*C(i,l)*C(j,r) (i*j>=k&&l<=i&&j&l

[计数dp] ural 1114. Boxes

题目链接: http://acm.timus.ru/problem.aspx?space=1&num=1114 1114. Boxes Time limit: 0.6 second Memory limit: 64 MB N boxes are lined up in a sequence (1 ≤ N ≤ 20). You have A red balls and B blue balls (0 ≤ A ≤ 15, 0 ≤ B ≤ 15). The red balls (and the blu

LibreOJ #2061. 「HAOI2016」放棋子

二次连通门 : LibreOJ #2061. 「HAOI2016」放棋子 /* LibreOJ #2061. 「HAOI2016」放棋子 MDZZ ... 错排 + 高精 */ #include <iostream> #include <cstdio> #include <vector> #include <iomanip> #include <cassert> #include <algorithm> #define int64 l

bzoj4563【HAOI2016】放棋子

4563: [Haoi2016]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 172  Solved: 119 [Submit][Status][Discuss] Description 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在 这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子 的限制,求有多少种方案. Input 第一行

HDU 4832 组合计数dp

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 509    Accepted Submission(s): 198 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘上的走法遵循十字

[HAOI2016]放棋子

题意 Here 思考 看第一眼:状压dp,再看范围gg 第二眼:普通dp,貌似可以直接递推? 其实就是个很裸的错排问题,写个博客顺便复习下~ 错排问题就是说一个 \(n\) 的排列,每个元素都满足 \(a[i] != i\),求方案数 记 \(f[n]\) 为 \(n\) 的错排方案数,我们可以考虑递推: 放第 \(n\) 个元素,有 \(n-1\) 种方法 假设第 \(n\) 个元素放在了 \(p\) 位置,那么放编号为 \(p\) 的元素: 放在 \(n\) 位置,对于剩下 \(n-2\)