• P3158 [CQOI2011]放棋子 [动态规划]


    放棋子

    题目描述见链接 .


    color{red}{正解部分}

    每个棋子都可以占据一行和一列, 且同一行同一列不能出现相同的棋子, 考虑 一个一个棋子放 不如 考虑 一种一种棋子放 ,

    F[i,j,k]F[i, j, k] 表示前 kk 种棋子占据了 iijj 列的方案数, g[i,j,k]g[i, j, k] 表示 kk 个棋子占据 iijj 列的 方案数,

    F[i,j,k]=l=0i1r=0j1F[l,r,k1](Nlil)(Mrjr)g[il,jr,k]          (il)(jr)a[k]F[i, j, k] = sumlimits_{l=0}^{i-1} sumlimits_{r=0}^{j-1} F[l, r, k-1] egin{pmatrix} N-l \ i-l end{pmatrix} egin{pmatrix} M-r \ j-r end{pmatrix} g[i-l, j-r, k] (i-l)(j-r) le a[k]

    g[i,j,k]g[i, j, k] 使用 容斥 递推, 使用 总方案数 减去 填不满的方案数 即为 合法方案数 .

    g[i,j,k]=(i×jk)l=1ir=1jg[l,r,k](il)(jr)g[i, j, k] = egin{pmatrix} i imes j \ k end{pmatrix} - sumlimits_{l=1}^i sumlimits_{r=1}^j g[l, r,k] egin{pmatrix} i \ l end{pmatrix} egin{pmatrix} j \r end{pmatrix}

    注意 g[i,j,k]g[i, j, k] 转移时要避免从自身转移过来, 即 ll rr 不能同时等于 ii jj .


    color{red}{实现部分}

    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 35;
    const int mod = 1e9 + 9;
    
    int N;
    int M;
    int K;
    int Mx;
    int a[maxn];
    int F[maxn][maxn][maxn];
    int g[maxn][maxn][maxn];
    int C[maxn*maxn][maxn*maxn];
    
    int main(){
    	scanf("%d%d%d", &N, &M, &K); 
            for(reg int i = 1; i <= K; i ++) scanf("%d", &a[i]);
            C[0][0] = 1;
            for(reg int i = 1; i <= N*M; i ++){
                    C[i][0] = 1;
                    for(reg int j = 1; j <= i; j ++) C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
            }
            F[0][0][0] = 1;
            for(reg int k = 1; k <= K; k ++)
                    for(reg int i = 1; i <= N; i ++)
                            for(reg int j = 1; j <= M; j ++){
                                    if(i*j < a[k]) continue ;
                                    int &t = g[i][j][k]; t = C[i*j][a[k]];
                                    for(reg int l = 1; l <= i; l ++)
                                            for(reg int r = 1; r <= j; r ++){
                                                    if(l == i && r == j) continue ;
                                                    t = (t - 1ll*g[l][r][k]*C[i][l]%mod*C[j][r]%mod + mod) % mod;
                                            }
                            }
            for(reg int k = 1; k <= K; k ++)
                    for(reg int i = 1; i <= N; i ++)
                            for(reg int j = 1; j <= M; j ++)
                                    for(reg int l = 0; l < i; l ++)
                                            for(reg int r = 0; r < j; r ++){
                                                    if((i-l)*(j-r) < a[k]) continue ;
                                                    int &t = F[i][j][k];
                                                    t = (t + 1ll*F[l][r][k-1]*C[N-l][i-l]%mod*C[M-r][j-r]%mod*g[i-l][j-r][k]) % mod;
                                            }
            int Ans = 0;
            for(reg int i = 1; i <= N; i ++)
                    for(reg int j = 1; j <= M; j ++) Ans = (Ans + F[i][j][K]) % mod;
            printf("%d
    ", Ans);
    	return 0;
    }
    
  • 相关阅读:
    wordpress调用函数大全
    Dedecms 数据库结构分析
    屏幕广播的实现(二)
    屏幕广播的实现(一)
    Alt+Ctrl+Del组合键的屏蔽
    关于钩子(HOOK)
    C# 线程入门 00
    C# 中 关键字 return break continue 详解
    Windows 网络命令
    vue自定义指令封装(加深印象)
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822417.html
Copyright © 2020-2023  润新知