In most professional sporting events,cheerleaders play a major role in entertaining the spectators. Their
roles aresubstantial during breaks and prior to start of play. The world cup soccer isno exception.
Usually thecheerleaders form a group and perform at the centre of the field. In additionto this group,
some of them areplaced outside the side line so they are closer to the spectators. Theorganizers would
like to ensure thatat least one cheerleader is located on each of the four sides. For thisproblem, we
will model theplaying ground as an M × N rectangular grid. The constraints for placingcheerleaders
are described below:
• There should beat least one cheerleader on each of the four sides. Note that, placing acheerleader
on a corner cellwould cover two sides simultaneously.
• There can be atmost one cheerleader in a cell.
• All thecheerleaders available must be assigned to a cell. That is, none of them can beleft out.
The organizerswould like to know, how many ways they can place the cheerleaders whilemaintaining
the aboveconstraints. Two placements are different, if there is at least one cell whichcontains a
cheerleader in oneof the placement but not in the other.
Input
The first line ofinput contains a positive integer T ≤ 50, which denotes the number of testcases. T
lines then followeach describing one test case. Each case consists of three nonnegativeintegers, 2 ≤ M,
N ≤ 20 and K ≤ 500.Here M is the number of rows and N is the number of columns in the grid. K
denotes the numberof cheerleaders that must be assigned to the cells in the grid.
Output
For each case ofinput, there will be one line of output. It will first contain the case numberfollowed by
the number of waysto place the cheerleaders as described earlier. Look at the sample output forexact
formatting. Notethat, the numbers can be arbitrarily large. Therefore you must output theanswers
modulo 1000007.
Sample Input
2
2 2 1
2 3 2
Sample Output
Case 1: 0
Case 2: 2
【题意】
m行n列的矩阵里放k个相同的石子,问有多少种放法?每个格子最多放一个石子,所有石子都要用完,并且第一行,第一列,最后一行,最后一列都要有石子。
【思路】
计数问题,但是很难直接计算,需要用到容斥原理。我们定义以下四个集合a:第一行不放;b:最后一行不放;c:第一列不放;d:最后一列不放。全集s是无限制的放置情况即c(m*n,k),则答案ans=s-|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<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxk = 500;
const int mod = 1000007;
ll c[maxk + 10][maxk + 10];
void init() {
memset(c, 0, sizeof(c));
c[0][0] = 1;
for (int i = 1; i <= maxk; 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 main() {
init();
int t;
ll m, n, k;
scanf("%d", &t);
for (int kase = 1; kase <= t; kase++) {
scanf("%lld%lld%lld", &m, &n, &k);
ll ans = 0;
for (int s = 0; s < 16; s++) {
int num = 0;
int row = m, col = n;
for (int j = 0; j < 4; j++) {
if (s >> j & 1) {
num++;
if (j < 2) row--;
else col--;
}
}
if (num & 1) ans = (ans + mod - c[row*col][k]) % mod;
else ans = (ans + c[row*col][k]) % mod;
}
printf("Case %d: %lld\n", kase, ans);
}
return 0;
}