UVA - 11806 Cheerleaders(容斥原理)

题意是n*m的格子上,放k个物品,且最上边的一行,最下面的一行,最左边的一行,最右边的一行,必须要放一个,问有多少种方案?

分析:从反方向思考,用总的方案数减去四周都不放的方案数。

用到容斥定理,减去有一边的方案,加上有两边的方案,减去有三边的方案,加上有四边的方案。

然后可以用四位的二进制数表示哪边没有物品,如:1000表示有一边没有棋子的方案

 

代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int MOD=1000007;
int C[1010][1010];
void init2()  //预处理组合数
{
    for(int i=0;i<=1000;i++)
        C[i][0]=1;
   for(int i=1;i<=1000;i++)
   {
       for(int j=1;j<=i;j++)
        C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
   }
}
int main()
{
    int n,m,k,a,row,col,sum,t,Case=0;
    init2();
    cin>>t;
    while(t--)
    {
        Case++;
      cin>>n>>m>>k;

        sum=0;
        for(int r=0;r<16;r++)
        {
            a=0,row=n,col=m;
            if(r&1)
            row--,a++;
            if(r&2)
            row--,a++;
            if(r&4)
            col--,a++;
            if(r&8)
            col--,a++;
            if(a&1)
            sum=((sum-C[row*col][k])%MOD+MOD)%MOD;
            else
            sum=(sum+C[row*col][k])%MOD;
        }
        printf("Case %d: ",Case);
        cout<<sum<<endl;    
    }
    return 0;
}

 

posted @ 2018-02-05 10:34  hinata_hajime  阅读(223)  评论(0编辑  收藏  举报