题意:
给定n、m、k三个数,n代表行数,m代表列数,k代表人数。
n*m的表格,一共有k个人,要求:
- 每个小格只能容纳一个人,所有人必须都在表格中。
- 第一行、第一列、最后一行、最后一列必须站人。
- 若夹角处站人,则代表此行和列都已站人。
题解:
利用容斥原理,设:
- S为总数。(n*m中选k个位置,即
)
- A为第一行没有站人。(少一行)
- B为最后一行没有站人。(少一行)
- C为第一列没有站人。(少一列)
- D为最后一列没有站人。(少一列)
文氏图如下:
我们要计算的就是,S减去ABCD覆盖部分。
容斥原理公式表示为:记:
代码:
#include <set> #include <map> #include <cmath> #include <stack> #include <queue> #include <vector> #include <string> #include <cstdio> #include <cstring> #include <sstream> #include <iomanip> #include <iostream> #include <algorithm> #define clr(str,x) memset(str,x,sizeof(str)) #define FRER() freopen("in.txt","r",stdin); #define FREW() freopen("out.txt","w",stdout); #define MAX_INF 0x7fffffff #define INF 0x3f3f3f3f #define maxn typedef long long int ll; using namespace std; const int mod = 1000007; int C[405][405]; int n,m,k,ans=0; void init() { for(int i=1; i<=400; i++) { C[i][0]=C[i][i]=1; for(int j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } int main() { // FRER() // FREW() init(); int T,kase=1; int s1,s2,s3,s4,s5; scanf("%d",&T); while(T--) { ans=0; scanf("%d%d%d",&n,&m,&k); if(k==0) { printf("Case %d: 0\n",kase++); continue; } s1=C[n*m][k]; s2=2*(C[n*(m-1)][k]+C[(n-1)*m][k])%mod; s3=(C[(n-2)*m][k]+4*C[n*m-n-m+1][k]+C[n*(m-2)][k])%mod; s4=2*(C[(n-2)*(m-1)][k]+C[(n-1)*(m-2)][k])%mod; s5=C[(n-2)*(m-2)][k]%mod; ans=s1-s2+s3-s4+s5; ans=(ans+10*mod)%mod;//防止取余后出现负数 printf("Case %d: %d\n",kase++,ans); } return 0; }