LightOJ - 1246 Colorful Board (思维+组合数+第二类stirling数)

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

4

0 0 1

0 0 2

5 5 2

5 5 1

Sample Output

Case 1: 1

Case 2: 2

Case 3: 2

Case 4: 0

题意:

给你一个(n+1)*(m+1)的棋盘(0<=n,m<=19),k种颜色。要把棋盘的每个格子涂上一种颜色,相同颜色的格子的曼哈顿距离均为偶数。求总共的涂法总数。

思路:

首先,容易发现是黑白棋盘问题,即按行列标和的奇偶性把棋盘分成两部分A和B(如果是一部分那答案就是k啦,见样例),每一部分用若干种颜色去涂,求方法总数。

因为棋盘必须涂色,我们设A部分有m1个格子,用x种颜色涂,B有m2个格子,用y种颜色涂,则问题变成了把m1个格子放到x种颜色(每种颜色必须用)的方法总数*把m2个格子放到y种颜色(每种颜色必须用)的方法总数*k种颜色中选x种颜色的方法总数*k-x种颜色中选y种颜色的方法总数。

即问题变成了n个有标志的球放进m个有区别的盒子,无一空盒的方案数+组合数。

前者即为第二类stirling数:

n个有标志的球放进m个有区别的盒子,无一空盒的方案数是:

这个式子和组合数都可以预处理,最后枚举一下x和y就可以了,不要忘了每一步都要取模。

代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=205;
const ll mo=1000000007;
ll n,m,k;
ll c[maxn][maxn];
ll v[maxn][maxn];
ll tmp,cnt,ans;
ll power(ll a,ll n)   //a的n次方mod
{
    ll ans=1;
    a=a%mo;
    while (n)
    {
        if(n&1) ans=(ans*a)%mo;
        n>>=1;
        a=(a*a)%mo;
    }
    return ans;
}
ll cal(ll n,ll m)
{
	ll tmp,ans=0;
	for(int k=0;k<=m;k++)
	{
		if(k&1) tmp=-1;
		else tmp=1;
		ans=(ans+tmp*c[m][k]%mo*power(m-k,n)%mo+mo)%mo;
	}
	return (ans+mo)%mo;
}
void init()
{
	c[0][0]=1;
	for(int i=1;i<maxn;i++)
	{
		c[i][0]=1;
		for(int j=1;j<=i;j++)
		c[i][j]=(c[i-1][j-1]+c[i-1][j])%mo;
	}
	for(int i=1;i<maxn;i++)
	{
		for(int j=1;j<=min(i,50);j++)
		{
			v[i][j]=cal(i,j);
			//cout<<i<<" "<<j<<" "<<v[i][j]<<endl;
		}
	}
}
int main()
{
    init();
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld",&n,&m,&k);
        n++;m++;
        tmp=(n*m+1)/2;
		cnt=n*m-tmp;
        if(!tmp||!cnt) ans=k;
        else if(k==1) ans=0;
		else {
			ans=0;
			for(int i=2;i<=k;i++)
			{
				for(int j=1;j<i;j++)
				{
					ans=(ans+c[k-j][i-j]*c[k][j]%mo*v[tmp][j]%mo*v[cnt][i-j]%mo)%mo;
				}
			}
		}
        printf("Case %d: %lld\n",cas++,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LSD20164388/article/details/88750543