题意:如何摆放拉拉队的问题,在矩形网格m*n中,k名拉拉队员,要求四周网格中each side有至少一名拉拉队员,corner有人算两边,问有多少种摆法?
思路:容斥;
c[m*n][k] -- c[(n-1)*m][k] U c[(n-1)*m][k]
U c[n*(m-1)][k] U c[n*(m-1)][k]
#include<cstdio> #include<iostream> #include<cstring> #define mod 1000007 using namespace std; typedef long long LL; //int C1[500][500]; int C[500][500]; void pre() //递推组合C[ ][ ] { memset(C,0,sizeof C); C[0][0]=1; for(int i=1;i<=400;i++) { C[i][i]=C[i][0]=1; for(int j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } int solve(int M,int N,int k) //容斥 { int sum=0; for(int i=1;i<(1<<4);i++) //枚举 { int n=N,m=M,bits=0; if(i&1) { bits++; n--; } if(i&(1<<1)) { bits++; m--; } if(i&(1<<2)) { bits++; n--; } if(i&(1<<3)) { bits++; m--; } if(bits%2==1) //判断奇偶 sum=(sum+C[n*m][k])%mod; else sum=(sum-C[n*m][k])%mod; } return ((C[N*M][k]-sum)%mod+mod)%mod; } int main() { int T; cin>>T; pre(); for(int cas=1;cas<=T;cas++) { int n,m,k; cin>>n>>m>>k; printf("Case %d: ",cas); if(k>n*m) printf("0\n"); else printf("%d\n",solve(n,m,k)); } return 0; }
时间: 2024-10-05 15:26:25