http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=31969
题意:
题意:在一个m*n的矩形网格里放k个相同的石子,问有多少种方法?每个格子最多放一个石子,所有石子都要放完,并且第一行、最后一行、第一列、最后一列都得有石子。
思路:假设满足第一行没有石子的方案集为A,最后一行没有石子的方案集为B,第一列没有石子的方案集为C,最后一列没有石子的方案集为D,全集为S,则所求答案就是“在S中但不在A,B,C,D任何一个集合中”的元素个数,这里就是运用容斥原理。 这里因为只有ABCD四种状态,可以用一个0-15的二进制位来表示其中的状态,(也就是计算该数二进制位中1的个数,奇减偶加)
另外一个地方,计算过程用到组合数,C(N,M) N最大400,M最大500,,直接暴力计算肯定不行了,用一个组合公式打表计算就好了
C(N,M)=C(N-1,M-1)+C(N-1,M); //初中的东西了,从N个人里面选M个人的方案数,可以分成两类:
(1)先选出一个人,保证一定选他,然后再从n-1个人选出m-1个人;
(2)确保不选刚才的那个人,直接从n-1个人里选出m个人;
两种情况是并起来就是C(N,M);
打表程序如下
int cc[404][505]; void pre() { int i,j; for (i=0;i<=400;i++) { cc[i][0]=1; //c(i,0)=1; } for (i=1;i<=400;i++) { for (j=1;j<=500;j++) cc[i][j]=(cc[i-1][j-1]+cc[i-1][j])%mod; } }
整个程序代码:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <iostream> #include <queue> #include <map> #include <set> #include <vector> using namespace std; const int mod =1000007; int cc[404][505]; void pre() { int i,j; for (i=0;i<=400;i++) { cc[i][0]=1; //c(i,0)=1; } for (i=1;i<=400;i++) { for (j=1;j<=500;j++) cc[i][j]=(cc[i-1][j-1]+cc[i-1][j])%mod; } } int main() { pre(); int t; int n,m,k; cin>>t; int cnt=1; int i; while(t--) { scanf("%d%d%d",&n,&m,&k); int ans=0; for (i=0;i<16;i++) { int r=n,c=m; int cun=0; if (i&1) {cun++;r--;} if (i&2) {cun++;r--;} if (i&4) {cun++;c--;} if (i&8) {cun++;c--;} if (cun%2) ans=(ans-cc[r*c][k]+mod)%mod; else ans= (ans+cc[r*c][k])%mod; } printf("Case %d: %d\n",cnt++,ans); } return 0; }