main
黄海 2 years ago
parent b17798a763
commit 973116883f

@ -37,9 +37,44 @@ int main() {
}
S = C[n * m][k]; // n*m个格子中找出k个格子站人就是所有方案数
/*
S
A
B
C
D
s1 =(A+B+C+D)
s2=(AB+AC+AD+BC+BD+CD)
s3=(ABC+ABD+ACD+BCD)
s4=(ABCD)
*/
// A:第一行没人即C[(n-1)*m,k]
// B:最后一行没人,即C[(n-1)*m,k]
// C:第一列没人C[n*(m-1),k]
// D:最后一列没人C[n*(m-1),k]
s1 = 2 * (C[n * (m - 1)][k] + C[(n - 1) * m][k]) % mod;
s2 = (C[(n - 2) * m][k] + 4 * C[n * m - n - m + 1][k] + C[n * (m - 2)][k]) % mod;
// AB:第一行最后一行没有人行少了2行列不变即C[(n-2)*m,k]
// AC:第一行第一列没有人行少了1行列少了一列即C[(n-1)*(m-1),k]
// AD:第一行最后一列没有人即C[(n-1)*(m-1),k]
// BC:最后一行第一列没有人即C[(n-1)*(m-1),k]
// BD:最后一行,最后一列没有人,即C[(n-1)*(m-1),k]
// CD:第一列,最后一列没有人,即C[n*(m-2),k]
// 中间4个是一样的4*C[(n-1)*(m-1),k]
s2 = (C[(n - 2) * m][k] + 4 * C[(n - 1) * (m - 1)][k] + C[n * (m - 2)][k]) % mod;
// ABC:第一行、最后一行、第一列没有人行少了2行列少了1列即C[(n-2)*(m-1),k]
// ABD:第一行、最后一行、最后一列没有人行少了2行列少了1列即C[(n-2)*(m-1),k]
// ABC+ABD=2*C[(n-2)*(m-1),k]
// ACD:第一行、第一列、最后一列没有人行少了1行列少了2列即 C[(n-1)*(m-2),k]
// BCD:最后一行、第一列、最后一列没有人行少了1行列少了2列即 C[(n-1)*(m-2),k]
// ACD+BCD=2*C[(n-1)*(m-2),k]
s3 = 2 * (C[(n - 2) * (m - 1)][k] + C[(n - 1) * (m - 2)][k]) % mod;
// 第一行第一列最后一行最后一列都不能站那么剩下n-2行m-2列需要在(n-2)*(m-2)这么多的格子里找出k个格子
s4 = C[(n - 2) * (m - 2)][k] % mod;
ans = (S - s1 + s2 - s3 + s4) % mod; // 容斥原理

@ -789,6 +789,7 @@ signed main() {
### [$UVA$ $11806$ $Cheerleaders$](https://vjudge.net/problem/UVA-11806)
<font color='red' size=4><b>考查了组合数公式、补集思想、容斥原理思想(不拘泥于质数+二进制枚举噢~</b></font>
#### 题意
给定$n、m、k$三个数,$n$代表行数,$m$代表列数,$k$代表人数。
@ -829,48 +830,88 @@ $s_3=(ABC+ABD+ACD+BCD)$
$s_4=(ABCD)$
```cpp {.line-numbers}
#include<iostream>
#include<cstdio>
#include<cstring>
#include <bits/stdc++.h>
using namespace std;
const int mod=1000007;
int data[510][510];
void get_data()
{
memset(data,0,sizeof(data));
for(int i=0;i<=500;i++)
data[i][0]=1;
for(int i=1;i<=500;i++)
for(int j=1;j<=i;j++)
data[i][j]=(data[i-1][j]+data[i-1][j-1])%mod;
}
const int mod = 1000007;
const int N = 410;
int C[N][N];
int n, m, k, ans;
/*
Sample Input
2
2 2 1
2 3 2
Sample Output
Case 1: 0
Case 2: 2
*/
int main() {
#ifndef ONLINE_JUDGE
freopen("UVA11806.in", "r", stdin);
#endif
// 预处理出组合数结果数组
for (int i = 1; i < N; 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()
{
int t,p=0;
cin>>t;
get_data();
while(t--)
{
p++;
int n,m,k;
int ans=0;
cin>>n>>m>>k;
for(int i=0;i<16;i++)
{
int cnt=0;
int row=n,col=m;
if(i&1) {row--;cnt++;}
if(i&2) {row--;cnt++;}
if(i&4) {col--;cnt++;}
if(i&8) {col--;cnt++;}
if(cnt%2==0) ans=(ans+data[row*col][k])%mod;
else ans=(ans+mod-data[row*col][k])%mod;
int T, cas = 1;
int S, s1, s2, s3, s4;
cin >> T;
while (T--) {
ans = 0; // 多组测试数据,每次注意清零
cin >> n >> m >> k; // n行,m列,k个人
if (k == 0) { // 一定要注意边界情况比如0个人
printf("Case %d: 0\n", cas++);
continue;
}
cout<<"Case "<<p<<": ";
cout<<ans<<endl;
S = C[n * m][k]; // n*m个格子中找出k个格子站人就是所有方案数
/*
S为总数
A为第一行没有站人
B为最后一行没有站人
C为第一列没有站人
D为最后一列没有站人
令:
s1 =(A+B+C+D)
s2=(AB+AC+AD+BC+BD+CD)
s3=(ABC+ABD+ACD+BCD)
s4=(ABCD)
*/
// A:第一行没人即C[(n-1)*m,k]
// B:最后一行没人,即C[(n-1)*m,k]
// C:第一列没人C[n*(m-1),k]
// D:最后一列没人C[n*(m-1),k]
s1 = 2 * (C[n * (m - 1)][k] + C[(n - 1) * m][k]) % mod;
// AB:第一行最后一行没有人行少了2行列不变即C[(n-2)*m,k]
// AC:第一行第一列没有人行少了1行列少了一列即C[(n-1)*(m-1),k]
// AD:第一行最后一列没有人即C[(n-1)*(m-1),k]
// BC:最后一行第一列没有人即C[(n-1)*(m-1),k]
// BD:最后一行,最后一列没有人,即C[(n-1)*(m-1),k]
// CD:第一列,最后一列没有人,即C[n*(m-2),k]
// 中间4个是一样的4*C[(n-1)*(m-1),k]
s2 = (C[(n - 2) * m][k] + 4 * C[(n - 1) * (m - 1)][k] + C[n * (m - 2)][k]) % mod;
// ABC:第一行、最后一行、第一列没有人行少了2行列少了1列即C[(n-2)*(m-1),k]
// ABD:第一行、最后一行、最后一列没有人行少了2行列少了1列即C[(n-2)*(m-1),k]
// ABC+ABD=2*C[(n-2)*(m-1),k]
// ACD:第一行、第一列、最后一列没有人行少了1行列少了2列即 C[(n-1)*(m-2),k]
// BCD:最后一行、第一列、最后一列没有人行少了1行列少了2列即 C[(n-1)*(m-2),k]
// ACD+BCD=2*C[(n-1)*(m-2),k]
s3 = 2 * (C[(n - 2) * (m - 1)][k] + C[(n - 1) * (m - 2)][k]) % mod;
// 第一行第一列最后一行最后一列都不能站那么剩下n-2行m-2列需要在(n-2)*(m-2)这么多的格子里找出k个格子
s4 = C[(n - 2) * (m - 2)][k] % mod;
ans = (S - s1 + s2 - s3 + s4) % mod; // 容斥原理
ans = (ans + mod) % mod; // 防止取余后出现负数
printf("Case %d: %d\n", cas++, ans); // 输出答案
}
return 0;
}

Loading…
Cancel
Save