From 973116883f58f7e2dd44805ec41ace4ee0d510c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B5=B7?= <10402852@qq.com> Date: Thu, 14 Dec 2023 09:18:43 +0800 Subject: [PATCH] 'commit' --- TangDou/AcWing_TiGao/T5/RongChi/UVA11806.cpp | 37 +++++- TangDou/Topic/容斥原理.md | 117 +++++++++++++------ 2 files changed, 115 insertions(+), 39 deletions(-) diff --git a/TangDou/AcWing_TiGao/T5/RongChi/UVA11806.cpp b/TangDou/AcWing_TiGao/T5/RongChi/UVA11806.cpp index e777e6a..99550e2 100644 --- a/TangDou/AcWing_TiGao/T5/RongChi/UVA11806.cpp +++ b/TangDou/AcWing_TiGao/T5/RongChi/UVA11806.cpp @@ -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; // 容斥原理 diff --git a/TangDou/Topic/容斥原理.md b/TangDou/Topic/容斥原理.md index 1831dd2..a7443ac 100644 --- a/TangDou/Topic/容斥原理.md +++ b/TangDou/Topic/容斥原理.md @@ -789,6 +789,7 @@ signed main() { ### [$UVA$ $11806$ $Cheerleaders$](https://vjudge.net/problem/UVA-11806) +考查了组合数公式、补集思想、容斥原理思想(不拘泥于质数+二进制枚举噢~) #### 题意 给定$n、m、k$三个数,$n$代表行数,$m$代表列数,$k$代表人数。 @@ -829,48 +830,88 @@ $s_3=(ABC+ABD+ACD+BCD)$ $s_4=(ABCD)$ ```cpp {.line-numbers} -#include -#include -#include +#include 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 "<