UVA_11806

    这个题目直接计算不大好算,但是反过来去计算不符合要求的局面则容易很多。

    我们不妨设A[i]表示我们规定其中i条边上不能放,而其他的地方随便放,所得的一个结果(比如i=2,我们要枚举是哪2条边没有放,然后其他地方随便放,可以用组合数求得结果,最后将每次枚举所得的结果加起来作为A[2]的值)。再设a[i]表示有且仅有i条边上没有放的情况数(比如i=2,同样是枚举哪2条边没有放,最后C(4,2)种枚举所得的情况之和才是a[2]的值)。

   我们想要的显然是a[1]+a[2]+a[3]+a[4],这就是所有不符合要求的情况,但是同样不好直接计算,但是A[i]却很好计算,我们只要枚举哪些边没有放,然后再用组合数计算其他地方随便放的方案数即可。我们列出通过上述规则计算所得的A[i]由哪些部分组成,比如A[1],我们按上述规则计算之后会发现a[1]算了1次,a[2]算了2次,a[3]算了3次,a[4]算了4次,也就是A[1]=a[1]+2*a[2]+3*a[3]+4*a[4]。同样的,可以得到A[2]=a[2]+3*a[3]+6*a[4],A[3]=a[3]+4*a[4],A[4]=a[4]。

    这样根据上面计算所得的A[1]、A[2]、A[3]、A[4]可以得到a[1]+a[2]+a[3]+a[4]=A[1]-A[2]+A[3]-A[4],这样就能得到我们所要的结果了。

#include<stdio.h>
#include<string.h>
#define MOD 1000007
int M, N, K, C[410][410];
void prep()
{
    memset(C, 0, sizeof(C));
    C[0][0] = 1;
    for(int i = 1; i <= 400; i ++)
    {
        C[i][0] = 1;
        for(int j = 1; j <= i; j ++) C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;
    }
}
void solve()
{
    int ans, A[5] = {0};
    for(int i = 1; i < 16; i ++)
    {
        int cnt = 0, t = 0, n = N, m = M;
        for(int j = 0; j < 4; j ++)
            if(i & 1 << j)
            {
                ++ cnt;
                if(j < 2) -- n;
                else -- m;
            }
        if(K <= n * m)
        {
            t = C[n * m][K];
            A[cnt] = (A[cnt] + t) % MOD;
        }
    }
    ans = A[1] - A[2] + A[3] - A[4];
    printf("%d\n", ((C[N * M][K] - ans) % MOD + MOD) % MOD);
}
int main()
{
    prep();
    int t;
    scanf("%d", &t);
    for(int tt = 1; tt <= t; tt ++)
    {
        scanf("%d%d%d", &M, &N, &K);
        printf("Case %d: ", tt);
        if(K > N * M) printf("0\n");
        else solve();
    }
    return 0;
}

 

 

posted on 2012-10-28 10:43  Staginner  阅读(484)  评论(0编辑  收藏  举报