Problem:
Score : 400 points

Problem Statement

There is a grid with N rows and N columns of squares. Let (i,j) be the square at the i-th row from the top and the j-th column from the left.

These squares have to be painted in one of the C colors from Color 1 to Color C. Initially, (i,j) is painted in Color c_{i,j}.

We say the grid is a good grid when the following condition is met for all i,j,x,y satisfying 1 \leq i,j,x,y \leq N:

If (i+j) \% 3=(x+y) \% 3, the color of (i,j) and the color of (x,y) are the same.

If (i+j) \% 3 \neq (x+y) \% 3, the color of (i,j) and the color of (x,y) are different.

Here, X \% Y represents X modulo Y.

We will repaint zero or more squares so that the grid will be a good grid.

For a square, the wrongness when the color of the square is X before repainting and Y after repainting, is D_{X,Y}.

Find the minimum possible sum of the wrongness of all the squares.

Constraints

1 \leq N \leq 500

3 \leq C \leq 30

1 \leq D_{i,j} \leq 1000 (i \neq j),D_{i,j}=0 (i=j)

1 \leq c_{i,j} \leq C

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N C
D_{1,1} ... D_{1,C}
:
D_{C,1} ... D_{C,C}
c_{1,1} ... c_{1,N}
:
c_{N,1} ... c_{N,N}

Output

If the minimum possible sum of the wrongness of all the squares is x, print x.

Sample Input 1

2 3
0 1 1
1 0 1
1 4 0
1 2
3 3

Sample Output 1

3

Repaint (1,1) to Color 2. The wrongness of (1,1) becomes D_{1,2}=1.

Repaint (1,2) to Color 3. The wrongness of (1,2) becomes D_{2,3}=1.

Repaint (2,2) to Color 1. The wrongness of (2,2) becomes D_{3,1}=1.

In this case, the sum of the wrongness of all the squares is 3.

Note that D_{i,j} \neq D_{j,i} is possible.

Sample Input 2

4 3
0 12 71
81 0 53
14 92 0
1 1 2 1
2 1 1 2
2 2 1 3
1 1 2 2

Sample Output 2

428

Solution in C (GCC 5.4.1) (judge verdict: Accepted)

#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 内部定数
#define D_ON			1										// 汎用フラグ - ON
#define D_OFF			0										// 汎用フラグ - OFF
#define D_COLOR_MAX		30										// 最大色数
#define D_GRID_MAX		500										// 最大グリッドサイズ
#define D_COLOR_GRP		3										// 別色のグループ数

// 内部変数
static int siCCnt;												// 色数
static int si2Grp[D_GRID_MAX * 2][D_COLOR_MAX + 5];				// 同色グループ(違和感合計)
static int siGCnt;												// 同色グループ数
static int siMin;												// 最小の違和感合計
static int si1NGColor[D_COLOR_MAX + 5];							// 選択不可色
static int si1SelColor[D_COLOR_GRP];							// 選択色

// 内部変数 - テスト用
#ifdef D_TEST
	static int siRes;
	static FILE *szpFpT, *szpFpA;
#endif

// 最小の違和感合計セット
int
fSetMin(
	int piGNo					// <I> 同色グループ番号 0～
	, int piSum					// <I> 違和感合計
)
{
	int i;

	// 終了チェック
	if (piGNo >= siGCnt) {

		// 最小の違和感合計
		if (siMin > piSum) {
			siMin = piSum;
		}

		return 0;
	}

	// 色の選択
	if (piGNo < D_COLOR_GRP) {				// 別色のグループ
		for (i = 1; i <= siCCnt; i++) {

			// 選択不可色
			if (si1NGColor[i] != D_OFF) {
				continue;
			}
			si1NGColor[i] = D_ON;
			si1SelColor[piGNo] = i;				// 選択色

			// 下位へ
			fSetMin(piGNo + 1, piSum + si2Grp[piGNo][i]);

			// 選択不可色
			si1NGColor[i] = D_OFF;
		}
	}
	else {									// 同色のグループ

		// 対象色
		int liColor = si1SelColor[piGNo % D_COLOR_GRP];

		// 下位へ
		fSetMin(piGNo + 1, piSum + si2Grp[piGNo][liColor]);
	}

	return 0;
}

// 実行メイン
int
fMain(
	int piTNo					// <I> テスト番号 1～
)
{
	int i, j, k;
	char lc1Buf[1024], lc1Out[1024];

	// データ初期化
	memset(si2Grp, 0, sizeof(si2Grp));							// 同色グループの違和感合計
	siMin = INT_MAX;											// 最小の違和感合計
	memset(si1NGColor, D_OFF, sizeof(si1NGColor));				// 選択不可色

	// テストファイルオープン
#ifdef D_TEST
	sprintf(lc1Buf, ".\\Test\\T%d.txt", piTNo);
	szpFpT = fopen(lc1Buf, "r");
	sprintf(lc1Buf, ".\\Test\\A%d.txt", piTNo);
	szpFpA = fopen(lc1Buf, "r");
	siRes = 0;
#endif

	// グリッドサイズ・色数取得
	int liGSize;
#ifdef D_TEST
	fgets(lc1Buf, sizeof(lc1Buf), szpFpT);
#else
	fgets(lc1Buf, sizeof(lc1Buf), stdin);
#endif
	sscanf(lc1Buf, "%d%d", &liGSize, &siCCnt);

	// 違和感取得
	int li2Icp[D_COLOR_MAX + 5][D_COLOR_MAX + 5];
	for (i = 1; i <= siCCnt; i++) {
		for (j = 1; j <= siCCnt; j++) {
#ifdef D_TEST
			fscanf(szpFpT, "%d", &li2Icp[i][j]);
#else
			fscanf(stdin, "%d", &li2Icp[i][j]);
#endif
		}
#ifdef D_TEST
		fgets(lc1Buf, sizeof(lc1Buf), szpFpT);
#else
		fgets(lc1Buf, sizeof(lc1Buf), stdin);
#endif
	}

	// グリッド取得、同色グループの違和感合計をセット
	for (i = 0; i < liGSize; i++) {
		for (j = 0; j < liGSize; j++) {
			int liColor;
#ifdef D_TEST
			fscanf(szpFpT, "%d", &liColor);
#else
			fscanf(stdin, "%d", &liColor);
#endif

			// 対象の同色グループ
			int *lipGrp = si2Grp[i + j];

			// 違和感合計を加算
			for (k = 1; k <= siCCnt; k++) {
				lipGrp[k] += li2Icp[liColor][k];
			}
		}
#ifdef D_TEST
		fgets(lc1Buf, sizeof(lc1Buf), szpFpT);
#else
		fgets(lc1Buf, sizeof(lc1Buf), stdin);
#endif
	}

	// 同色グループ数
	siGCnt = liGSize * 2 - 1;

	// 最小の違和感合計セット
	fSetMin(0, 0);

	// 結果セット
	sprintf(lc1Out, "%d\n", siMin);

	// 結果表示
#ifdef D_TEST
	fgets(lc1Buf, sizeof(lc1Buf), szpFpA);
	if (strcmp(lc1Buf, lc1Out)) {
		siRes = -1;
	}
#else
	printf("%s", lc1Out);
#endif

	// テストファイルクローズ
#ifdef D_TEST
	fclose(szpFpT);
	fclose(szpFpA);
#endif

	// テスト結果
#ifdef D_TEST
	if (siRes == 0) {
		printf("OK %d\n", piTNo);
	}
	else {
		printf("NG %d\n", piTNo);
	}
#endif

	return 0;
}

int
main()
{

#ifdef D_TEST
	int i;
	for (i = D_TEST_SNO; i <= D_TEST_ENO; i++) {
		fMain(i);
	}
#else
	fMain(0);
#endif

	return 0;
}