ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

放棋子:组合数/dp/容斥原理

2019-07-09 21:51:10  阅读:198  来源: 互联网

标签:31 容斥 yy xx num 棋子 dp


题目传送门

啊又是一个考场上没拿到的水题,差一步!!

组合数,先打个杨辉三角吧。

显然棋子应该一种一种的放,这很dp。

而且棋子一旦放下,那么它所在的行列就只能放这种颜色的棋子了。

设dp[i][x][y]表示正在放第i种颜色的棋子,还有x行y列没有放过棋子。

我们枚举给第i种颜色的棋子一共安排xx行yy列,需要的组合数是:

从剩余的x行中选出xx行,列同理,再从xx*yy个位置里放num[i]个棋子

但是最后一个并不是简单的组合数:你要保证你的放法把拿出的xx行yy列都用到了。

这个怎么求?感觉像容斥嘛?设g[num][xx][yy]表示用num个棋子放满xx行yy列的方案数

g[num][xx][yy]=C(xx*yy,num)-∑x=1->xxy=1->yyg[num][x][y];(x!=xx||y!=yy)

没有初状态,它会用那个组合数减去若干个0给你弄出来。

没了。。。吧。。。应该都能懂了叭?

 1 #include<cstdio>
 2 #define mod 1000000009
 3 int c[901][901],dp[11][31][31],g[11][31][31],n,m,k,num[11],ans;
 4 int main(){
 5     dp[0][0][0]=1;
 6     scanf("%d%d%d",&n,&m,&k);
 7     for(int i=1;i<=k;++i)scanf("%d",&num[i]);
 8     for(int i=0;i<=900;++i)c[i][0]=1;
 9     for(int i=1;i<=900;++i)for(int j=1;j<=i;++j)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
10     for(int i=1;i<=k;++i)for(int x=1;x<=n;++x)for(int y=1;y<=m;++y){
11         g[i][x][y]=c[x*y][num[i]];
12         for(int xx=1;xx<=x;++xx)for(int yy=1;yy<=y;++yy)if(xx!=x||yy!=y)
13             g[i][x][y]=(g[i][x][y]-1ll*g[i][xx][yy]*c[x][xx]%mod*c[y][yy]%mod+mod)%mod;
14         for(int xx=i-1;xx<x;++xx)for(int yy=i-1;yy<y;++yy)
15             dp[i][x][y]=(dp[i][x][y]+1ll*dp[i-1][xx][yy]*c[n-xx][x-xx]%mod*c[m-yy][y-yy]%mod*g[i][x-xx][y-yy]%mod)%mod;
16     }
17     for(int x=1;x<=n;++x)for(int y=1;y<=m;++y)ans=(ans+dp[k][x][y])%mod;
18     printf("%d",ans);
19 }
多多取模

标签:31,容斥,yy,xx,num,棋子,dp
来源: https://www.cnblogs.com/hzoi-DeepinC/p/11160667.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有