D - Cheerleaders
题目链接:https://vjudge.net/contest/154063#problem/D
题目大意:
给你一个 n∗m 的方格,现在有 k 个相同石子,我们要将这 k 个石子完全放入 n∗m 中,
要求的是第一行、第一列、最后一行和最后一列中必须有石子,求的是方案数。
解题思路:
我们来分析一下这个题目,因为题目中要求的是第一行、第一列、最后一行和最后一列中必须有石子,那么我们现在应该从反面考虑也就是利用容斥原理解决这个问题,这个是很容易想到的,那么现在我们设 4 个事件:
A:表示的是第一行中没有石子的方案数
B:表示的是第一列中没有石子的方案数
C:表示的是最后一行中没有石子的方案数
D:表示的是最后一列中没有石子的方案数
那么我们要求的方案数就是:
|A∪B∪C∪D|=|A|+|B|+|C|+|D|−|A∩B|−|A∩C|−|A∩D|−|B∩C|−|B∩D|−|C∩D|+|A∩B∩C|+|A∩B∩D|+|A∩C∩D|+|B∩C∩D|−|A∩B∩C∩D|
然后利用二进制枚举总的状态就可以了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MOD=1000007; const int MAX=505; int c[MAX][MAX]; void plzh() { for(int i=0;i<=500;i++) { c[i][0]=1; c[i][i]=1; } for(int i=2; i<=500; i++) { for(int j=1; j<i; j++) { c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD; } } } int main() { plzh(); int t,s=0; int n,m,k; scanf("%d",&t); while(t--) { s++; scanf("%d%d%d",&n,&m,&k); int sum=0; for(int i=0; i<16; i++) { int x=n,y=m,cnt=0; if(i&1) { x--; cnt++; } if(i&2) { y--; cnt++; } if(i&4) { x--; cnt++; } if(i&8) { y--; cnt++; } if(cnt&1) sum= ((sum - c[x*y][k])%MOD+MOD)%MOD; else sum=(sum+c[x*y][k])%MOD; } printf("Case %d: %d ",s,sum); } return 0; }