• [BZOJ3294]放棋子


    放棋子

    题目描述

    image

    输入格式

    输入第一行为两个整数n, m, c,即行数、列数和棋子的颜色数。
    第二行包含c个正整数,即每个颜色的棋子数。
    所有颜色的棋子总数保证不超过nm。
    N,M<=30 C<=10 总棋子数有大于250的情况

    输出格式

    输出仅一行,即方案总数除以 1,000,000,009的余数。

    样例

    样例输入

    4 2 2
    3 1

    样例输出

    8

    数据范围与提示

    30% n,m<=10

    看题解,觉得这道题挺水的,然而考试时候的我,只能打出来20分TLE的暴力

    又是一道出现在组合数里的DP,不过跟地精比,这道题跟跟组合数关系还稍微大一点

    既然是DP,我们先来想一想怎么进行状态转移

    我们用$shu[o]$表示第$o$种棋子的数量,$g[o][i][j]$表示第$o$种棋子,占了$i$行$j$列,那首先想到的就是$g[o][i][j]=C_{i{ imes}j}^{shu[o]}$,但是仔细想一想这样算的话,这$shu[o]$个棋子可能并没有占满$i$行$j$列,你可能就只用了$x$行$y$列($x<i$,$j<y$),这个时候要怎么办?答案容斥,也不知道为啥,最近老碰见它,我还老想不起来它,怎么斥就很明显了,用基础的$C_{i{ imes}j}^{shu[o]}$-每一个不占满的情况,所以就有$g[o][i][j]=C_{i{ imes}j}^{shu[o]}-{sum}g[o][x][y]{ imes}C_i^x{ imes}C_j^y$,保证$x{leq}i$,$y{ge}j$且$x=i$,$y=j$不同时满足,这很显然吧,然而我卡了好久,说一句吧,如果两个等号同时成立,那你就把要的也同时容斥掉了,为什么乘两个C应该就更好理解了吧,关于C的计算,直接杨辉三角,两层循环跑一遍就可以

    我们算出来第$o$种之后,答案要的是前C种,那就需要算前o种的,照葫芦画瓢,我们用$f[o][i][j]$表示前$o$种棋子,占$i$行$j$列的方案数,这个就好想了,$f[o][i][j]={sum}f[o-1][x][y]{ imes}g[o][i-x][j-y]{ imes}C_i^x{ imes}C_j^y$,最后把所有的$f[C][i][j]$加起来就是最后的答案了

    关于暴搜:我暴搜就只拿到了20分,就是把每个棋子都当作不同的去放,最后除以全排列就可以了,剪枝我没太剪成,想练一练暴搜的可以试一试这道题,还算是需要注意的细节比较多的

    要开始集训了,希望过完这个暑假可以场场不暴零了吧

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #define maxz 11
     5 #define maxn 31
     6 #define ll long long
     7 const long long mod=1e9+9;
     8 using namespace std;
     9 int n,m,z;
    10 ll ans;
    11 int shu[maxz];
    12 ll C[maxn*maxn][maxn*maxn];
    13 ll g[maxz][maxn][maxn],f[maxz][maxn][maxn]={1};
    14 int main()
    15 {
    16     scanf("%d%d%d",&n,&m,&z);
    17     for(int i=1;i<=z;++i)  scanf("%d",&shu[i]);
    18     int ls=n*m+1;
    19     for(int i=0;i<=ls;++i)
    20     {
    21         C[i][0]=1;  C[i][i]=1;
    22         for(int j=1;j<=i;++j)  C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    23     }
    24     for(int o=1;o<=z;++o)
    25         for(int i=1;i<=n;++i)
    26             for(int j=1;j<=m;++j)
    27             {
    28                 if(i*j<shu[o])  continue;
    29                 if(max(i,j)>shu[o])  continue;
    30                 g[o][i][j]=C[i*j][shu[o]]%mod;
    31                 for(int x=1;x<=i;++x)
    32                     for(int y=1;y<=j;++y)
    33                     {
    34                         if(i==x&&j==y)  continue;
    35                         g[o][i][j]=(g[o][i][j]-(g[o][x][y]*C[i][x]*C[j][y])%mod)%mod;
    36                     }
    37             }
    38     for(int o=1;o<=z;++o)
    39         for(int i=1;i<=n;++i)
    40             for(int j=1;j<=m;++j)
    41             {
    42                 if(i*j<shu[o])  continue;
    43                 for(int x=0;x<=i;++x)
    44                     for(int y=0;y<=j;++y)
    45                     {
    46                         if(i==x&&j==y)  continue;
    47                         ll ls1=(C[i][x]*C[j][y])%mod;
    48                         ll ls2=(g[o][i-x][j-y]*ls1)%mod;
    49                         f[o][i][j]=(f[o][i][j]+(f[o-1][x][y]*ls2)%mod)%mod;
    50                     }
    51             }
    52     for(int i=1;i<=n;++i)
    53         for(int j=1;j<=m;++j)
    54             ans=(ans+((f[z][i][j]*C[n][i]%mod)*C[m][j])%mod)%mod;
    55     printf("%lld
    ",ans);
    56     return 0;
    57 }
  • 相关阅读:
    在Spring Boot中使用Swagger2
    初识设计模式之简单工厂模式、工厂方法模式、抽象工厂模式
    基于百度AI接口的微信小程序-数字识别
    微信小程序实现自定义遮罩
    微信小程序之视图容器movable-view实现拖拽功能
    微信小程序之map组件初体验
    基于百度AI接口的微信小程序-人脸搜索
    基于百度AI接口的微信小程序-图像搜索
    微信小程序实现上拉加载(分页加载)
    微信小程序实现下拉刷新
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11166608.html
Copyright © 2020-2023  润新知