题目链接:
题目意思:
在一个m行n列的矩形方格里放置k个相同的石子,每个格最多放一个石子,所有石子都要放完,并且第一行,最后一行,第一列,最后一列都得有石子,问一共有多少种放法?
题目分析:
一开始想到的是分类,但是由于四个角上的棋子分类比较复杂,就放弃了。后来想到了容斥原理。
设满足“第一行没有石子”的方案为A,满足“第最后一行没有石子”的方案为B,满足“第一列没有石子”的方案为C,满足“第最后一列没有石子”的方案为D。在程序中利用二进制来表示ABCD的所有搭配,并满足”奇减偶加“。
AC代码:
#include <stdio.h>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 500;
const int mod = 1000007;
int c[maxn+10][maxn+10];
int main()
{
int t,m,n,k;
memset(c,0,sizeof(c));
c[0][0] = 1;
for(int i=0;i<=maxn;i++)
{
c[i][0] = c[i][i] = 1; //边界条件
for(int j = 1;j<i;j++)
c[i][j] = (c[i-1][j] + c[i-1][j-1])%mod;
}
int cnt = 0;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
int sum = 0;
for(int s=0;s<=15;s++)
{
int h = m; //h,l的赋值在for循环内部,hl表示行列数
int l = n;
int b = 0;
if(s & 1) {h--; b++;} //表示组合中有A,下面以此类推
if(s & 2) {h--; b++;}
if(s & 4) {l--; b++;}
if(s & 8) {l--; b++;}
if(b & 1) //奇数
sum = (sum + mod-c[l*h][k])%mod; //加上取余的数,避免产生负值
else
sum = (sum + c[l*h][k]) % mod;
}
printf("Case %d: %d\n",++cnt,sum);
}
return 0;
}