lightoj 1246 - Colorful Board

You are given a rectangular board. You are asked to draw M horizontal lines and N vertical lines in that board, so that the whole board will be divided into (M+1) x (N+1) cells. So, there will be M+1rows each of which will exactly contain N+1 cells or columns. The yth cell of xth row can be called as cell(x, y). The distance between two cells is the summation of row difference and column difference of those two cells. So, the distance between cell(x1, y1) and cell(x2, y2) is

|x1 - x2| + |y1 - y2|

For example, the distance between cell (2, 3) and cell (3, 2) is |2 - 3| + |3 - 2| = 1 + 1 = 2.

After that you have to color every cell of the board. For that you are given K different colors. To make the board more beautiful you have to make sure that no two cells having the same color can have odd distance between them. For example, if you color cell (3, 5) with red, you cannot color cell (5, 8) with red, as the distance between them is 5, which is odd. Note that you can keep some color unused, but you can't keep some cell uncolored.

You have to determine how many ways to color the board using those K colors.

Input

Input starts with an integer T (≤ 20000), denoting the number of test cases.

Each case starts with a line containing three integers M, N, K (0 ≤ M, N ≤ 19, 1 ≤ K ≤ 50).

Output

For each case, print the case number and the number of ways you can color the board. The result can be large, so print the result modulo 1000000007.

Sample Input

Output for Sample Input

4

0 0 1

0 0 2

5 5 2

5 5 1

Case 1: 1

Case 2: 2

Case 3: 2

Case 4: 0



让你把一个(n+1)x(m+1)的矩阵涂上颜色,要求曼哈顿距离为奇数的两个格子不能涂相同的颜色,问你用K种颜色可以有多少种涂色的方法,颜色可以不用完。

思路就是把矩阵分为两块,在这两块中的任意两个格子的曼哈顿距离都是偶数,所以就可以涂的颜色不受限制。

首先是要处理出来组合数,然后就是dp[i][j]表示涂了i个格子,有j种颜色的方法数。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
#define mod 1000000007
using namespace std;

LL dp[220][60],c[60][60];

void init()
{
    int i,j;
    c[1][0] = c[1][1] = 1;
    for(i=2;i<=50;i++)
    {
        c[i][0] = c[i][i] = 1;
        for(j=1;j<i;j++)
            c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
    }
    for(i=1;i<=210;i++)
    {
        dp[i][1] = 1;
        for(j=2;j<=50;j++)
        {
            dp[i][j] = (dp[i-1][j-1] + dp[i-1][j])*j%mod;
            //dp[i][j]可以由dp[i-1][j]选j种颜色中的一种转移过来
            //因为dp[i-1][j-1]前j-1种颜色的选法有j种,所以也乘j
        }
    }
}

int main(void)
{
    init();
    int T,n,m,i,j,k;
    scanf("%d",&T);
    int cas = 1;
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        printf("Case %d: ",cas++);
        if(n == 0 && m == 0)
        {
            printf("%d\n",k);
            continue;
        }
        n++,m++;
        int x = n*m/2;
        int y = n*m-x;
        LL ans = 0;
        for(i=1;i<k;i++)
        {
            for(j=1;j<=k-i;j++)
            {
                ans = (ans + (c[k][i]*dp[x][i]%mod)*(c[k-i][j]*dp[y][j]%mod)%mod)%mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值