Cheerleaders UVA - 11806

原题链接
考察:容斥原理
只有我不会的容斥原理.
错误思路:
  正向考虑,然后根本算不出来
思路:
  这里主要是抽象成四个条件:

  1. 第一行没有人
  2. 最后一行没有人.
  3. 第一列没有人
  4. 最后一列没有人.
      我想的是分情况讨论边角的情况,结果是情况太复杂了.这里的容斥主要是抽象出四个条件.
      而且处理剩余位置也很妙,每次条件就是少了一行或者一列,我们不要单独讨论格子数目,只需要讨论行列数即可.
    注意取模减法一定+模数,存在取模后反而变小的情况

Code

#include <iostream> 
#include <cstring>
using namespace std;
typedef long long LL;
const int M = 1000007,N = 510;
int n,m,k,C[N][N];
void init()
{
	for(int i=0;i<N;i++)
	  for(int j=0;j<=i;j++)
	    if(!j) C[i][j] = 1;
	    else C[i][j] = ((LL)C[i-1][j-1]+C[i-1][j])%M;
}
int main()
{
	int T,kcase =0;
	scanf("%d",&T);
	init();
	while(T--)
	{
		scanf("%d%d%d",&n,&m,&k);
		if(n*m<k||k==1) {printf("Case %d: 0\n",++kcase);continue;} 
		LL res = C[n*m][k];
		for(int i=1;i<1<<4;i++)
		{
			int x = n,y=m,cnt=0;//妙极了的处理方式
			for(int j=0;j<4;j++)
			  if(i>>j&1) 
			  {
			  	if(!j||j==2) x--;
			  	if(j==1||j==3) y--;
			  	cnt++;
			  }
			if(cnt&1) res-=C[x*y][k];
			else res+=C[x*y][k];
			res=(res+M)%M;
		}
		printf("Case %d: %d\n",++kcase,res);
	}
	return 0;
}

posted @ 2021-06-17 19:38  acmloser  阅读(34)  评论(0编辑  收藏  举报