首页 > 代码库 > uva 11806 Cheerleaders(容斥)

uva 11806 Cheerleaders(容斥)

题意:如何摆放拉拉队的问题,在矩形网格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;
}



uva 11806 Cheerleaders(容斥)