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# (Mono 4.6.2.0) (judge verdict: Accepted)

// #define DEBUG

using System;

public class Program
{
  const int NMAX = 505;
  const int CMAX = 32;
  const int INF = (int)1e9;
  private static int[,] dat, D;
  private static int N,C;
  private static int[] dp0, dp1, dp2;

  private static int ans = INF;
  static int colorMod(int i, int c0, int c1, int c2){
    switch(i % 3){
      case 0:
      return c0;
      case 1:
      return c1;
      case 2:
      return c2;
      default:
      Console.WriteLine("error: Wrong Modular");
      return -1;
    }
  }
  static int calcDiff(int c0, int c1, int c2){
    if(dp0[c0] != -1 && dp1[c1] != -1 && dp2[c2] != -1)
      return dp0[c0] + dp1[c1] + dp2[c2];
    int ret = 0;
    dp0[c0] = dp1[c1] = dp2[c2] = 0;
    for(int i = 1; i <= N; ++i){
      for(int j = 1; j <= N; ++j)
        {
          // Console.WriteLine("dat[{0}, {1}] => {2}", i, j, dat[i, j]);
          // Console.WriteLine("colorMod[{0}, {1}, {2}, {3}] => {4}",
           // i + j, c0, c1, c2, colorMod(i + j, c0, c1, c2));
          int mod = colorMod(i + j, c0, c1, c2);
          ret += D[dat[i, j], mod];
          switch((i + j) % 3){
            case 0:
            dp0[c0] += D[dat[i ,j], mod];
            break;
            case 1:
            dp1[c1] += D[dat[i ,j], mod];
            break;
            case 2:
            dp2[c2] += D[dat[i ,j], mod];
            break;
          }
        }
    }
    #if DEBUG
        Console.WriteLine("calcDiff({0}, {1}, {2}) => {3}",
          c0, c1, c2, ret);
    #endif
    return ret;
  }

  static void solve(){
    // Console.WriteLine("solve() begin N: {0}", N);
    dp0 = new int[C + 1];
    dp1 = new int[C + 1];
    dp2 = new int[C + 1];
    for(int i = 0; i <= C; ++i) dp0[i] = dp1[i] = dp2[i] = -1;

    for(int i = 1; i <= C; ++i){
      for(int j = i + 1; j <= C; ++j){
        for(int k = j + 1; k <= C; ++k)
        {
          ans = Math.Min(ans, calcDiff(i, j, k));
          ans = Math.Min(ans, calcDiff(i, k, j));
          ans = Math.Min(ans, calcDiff(j, i, k));
          ans = Math.Min(ans, calcDiff(j, k, i));
          ans = Math.Min(ans, calcDiff(k, i, j));
          ans = Math.Min(ans, calcDiff(k, j, i));
        }
      }
    }
  }
  static void debug(){
    Console.WriteLine("D: ");
    for(int i = 0; i < C; ++i){
      for(int j = 0; j < C; ++j){
        Console.Write("{0} ", D[i+1, j+1]);
      }
      Console.Write("\n");
    }
    Console.WriteLine("dat: ");
    for(int i = 0; i <= N + 1; ++i){
      for(int j = 0; j <= N + 1; ++j){
        Console.Write("{0} ", dat[i, j]);
      }
      Console.Write("\n");
    }
    Console.WriteLine("ans: ");
  }

  static public void Main ()
  {
    String[] NC = Console.ReadLine().Split(' ');
    N = int.Parse(NC[0]);
    C = int.Parse(NC[1]);

    D = new int[C + 1, C + 1];
    for(int i  = 0; i < C; ++i){
      String[] Di = Console.ReadLine().Split(' ');
      for(int j = 0; j < C; ++j){
        D[i + 1, j + 1] = int.Parse(Di[j]);
      }
    }

    dat = new int[N + 2, N + 2];
    for(int i  = 0; i < N; ++i){
      String[] ci = Console.ReadLine().Split(' ');
      for(int j = 0; j < N; ++j){
        dat[i + 1, j + 1] = int.Parse(ci[j]);
      }
    }
    solve();
    #if DEBUG
      debug();
    #endif
    Console.WriteLine (ans);
  }
}