棋盘
来源:互联网 发布:淘宝iphone官换机 编辑:程序博客网 时间:2024/04/27 14:39
棋盘
题目描述
给你一个R行C列的棋盘,每个格子可以染成黑色或白色。如果一个染色方案使棋盘的某一行或某一列全为白色,那么这个染色方案使非法的,否则是合法的。
请问:有多少种合法的染色方案?由于答案可能非常大,请你输出答案对1,000,000,007取模后的结果。
【约定】
30%的数据满足,1≤R, C≤4;
100%的数据满足,1≤R, C≤2000。
输入格式 2161.in
一行两个整数R, C。
输出格式 2161.out
合法的染色方案数对1,000,000,007取模后的结果。
输入样例 2161.in
【输入样例1】
2 2
【输入样例2】
3 3
【输入样例3】
123 321
输出样例 2161.out
【输出样例1】
7
【输出样例2】
265
【输出样例3】
383377374
此题用容斥原理做,有两种办法。
方法一:行、列同时容斥
直接求合法方案数比较难。不妨换个思路: 用全部方案数减去非法方案数。
全部方案数自然为2^(n*m)。
至于非法方案,就要用到容斥原理了。我们可以规定好空的行列,其余的格子不做规定,就是某些情况的非法方案数了。
1.可能有某一行是空的,于是减去2^[(n-1)*m]*c[n][1]
2.可能有某一列是空的,于是减去2^[(m-1)*n]*c[m][1]
3.可能有一行,一列是空的,这样的情况在之前进行了重复的计算,减多了。于是加上c[n][1]*c[m][1]*{2^[(m-1)*(n-1)]}
4.可能有一行,两列是空的。在算3.的时候,加多了。因此应减去c[n][1]*c[m][2]*{2^[(m-2)*(n-1)]}
……
通过分析不难发现,假设我们枚举有i行,j列为空,那么,当i+j为奇数时,应加上方案数;否则减去方案数。
最后答案即为所求。
代码如下:
#include#include typedef long long LL;#define Mod 1000000007LL C[2050][2050], pow2[4000050];int main(){int N, M;scanf("%d%d", &N, &M);C[0][0] = 1;for (int i = 1; i <= N || i <= M; ++ i){C[i][0] = 1;for (int j = 1; j <= i; ++ j) C[i][j] = (C[i-1][j-1] + C[i-1][j]) % Mod;}pow2[0] = 1;for (int i = 1; i <= N*M; ++ i) pow2[i] = pow2[i-1] * 2 % Mod;LL Ans = 0;for (int i = 0; i <= N; ++ i) for (int j = 0; j <= M; ++ j)Ans = (Ans + (((i+j)&1)*(-2)+1) * pow2[(N-i)*(M-j)] % Mod * C[N][i] % Mod * C[M][j] % Mod) % Mod;printf("%d\n", int( (Ans + Mod) % Mod ));return 0;}
方法二、只对列进行容斥
假设本题只有行的限制,运用排列组合的知识,不难求得方案数为(2^m-1)^n。
现在增加了一个列的限制,需要两个条件都要保证。其实,就是上述问题的一个变种。
现在同样的思路,合法方案数=总方案数-非法方案数
既然列不能为空,那我就将空的列枚举出来,在此基础上,规定每行都不能空。
假设有1列为空,那么这些是非法方案,因此ans-=c[m][1]*{[2^(m-1)-1]^n}
假设有2列为空,这些方案在算1列为空时重复了,因此ans+=c[m][2]* {[2^(m-2)-1]^n}
……
以此类推,我们枚举空的列数为j,c[m][j]*{[2^(m-j)-1]^n}种方案。j为奇数时,加上它;否则减去它即可。
代码如下:
#include#include using namespace std;const int MAXN=2005;long long n,m;long long c[MAXN][MAXN];long long mod=1e9+7,ans,a;void C(){for(int i=0;i<=m;i++){for(int j=0;j<=i;j++){if(j==0||j==i)c[i][j]=1;elsec[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;}}}long long g(long long m){long long a=1,b;for(int i=1;i<=m;i++)a=(a*2)%mod;a=(a+mod-1)%mod;b=1;for(int i=1;i<=n;i++)b=(b*a)%mod;return b;}long long f(int n,int m){long long num=0;for(int i=1;i<=m;i++){if(i%2==1)num=(num+c[m][i]*g(m-i)%mod)%mod;elsenum=(num+mod-c[m][i]*g(m-i)%mod)%mod;}return num;}int main(){cin>>n>>m;C();ans=g(m);ans=(ans+mod-f(n,m))%mod;cout<
这题,可以说是转化思想的成功典范。合法方案=总方案-非法方案的思想 普遍应用于题目中!
本题,让我更深一点地了解了容斥原理。在计算某些方案时,先不要给它太多的限制,先不考虑可能重复的情况。反正,多加了的,可以减回来;多减了的,可以加回来。弄清楚几点关键的:计算方案数时,给了哪些限制;什么与什么会造成重复;在什么情况下要减、加。将问题想清楚,方法、答案就显而易见了。
- 棋盘
- 棋盘!!!
- 棋盘
- 棋盘
- 棋盘
- 棋盘
- 棋盘覆盖
- 棋盘覆盖
- 棋盘覆盖
- 棋盘问题
- 棋盘问题
- 棋盘覆盖
- 棋盘覆盖
- 棋盘覆盖
- 棋盘覆盖
- 棋盘问题
- 棋盘覆盖
- 棋盘覆盖
- Android Studio中如何解决重复依赖导致的app:transformClassesWithJarMergingForDebug
- Eclipse自动生成作者、日期注释等功能设置
- ACM新人入门指导
- MongoDB 常用命令与经验
- SQL语句之DDL和DML
- 棋盘
- C++实现的插入排序
- uiautomatorviewer出现Unable to connect to adb. Check if adb is installed correctly的解决方法
- Ubuntu 16.04安装Brackets 失败,缺失libgcrypt11,解决办法
- 移动端 关于 键盘将input 框 顶上去的解决思路
- 4.jquery
- OLTP与OLAP的区别精简总结
- Latex中图形的引用和插入
- leetcode--Intersection of Two Linked Lists