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 Rust (1.15.1) (judge verdict: Accepted)

use std::io;
//use std::collections::HashMap;
//use std::collections::BinaryHeap;
//use std::collections::HashSet;
//use std::mem; // mem::swap(&mut x,&mut y);
use std::cmp; // cmp::max,cmp::min

// Rust memo: https://hackmd.io/i0lQY1OKTDW1t66TECOmiw?both

#[allow(dead_code)]
fn read_line() -> String{
    let mut s = String::new();
    io::stdin().read_line(&mut s).unwrap();
    s.trim().to_string()
}

#[allow(dead_code)]
fn read_charvec() -> Vec<char>{
    read_line().chars().collect()
}

#[allow(dead_code)]
fn read_ints() -> Vec<i64>{
    let s = read_line();
    let split:Vec<&str> = s.split(" ").collect();
    split.iter().map(|&x| x.to_string().parse().unwrap()).collect()
}

#[allow(dead_code)]
fn read_int() -> i64{
    read_ints()[0]
}

#[allow(dead_code)]
fn reverse(s: &String) -> String{
    s.chars().rev().collect::<String>()
}

#[allow(dead_code)]
fn read_lines(n:i64) -> Vec<String>{
    let mut xs = Vec::new();

    for _i in 0..n{
        xs.push(read_line());
    }

    xs
}

#[allow(dead_code)]
fn read_ints2(n:i64) -> Vec<i64>{
    read_lines(n).iter().map(|x| x.parse().unwrap()).collect()
}

#[allow(dead_code)]
fn arange(start:i64,end:i64,step:i64) -> Vec<i64>{
    let mut ret = Vec::new();
    let mut i = start;

    while i < end{
        ret.push(i);
        i += step;
    }

    ret
}

#[allow(dead_code)]
const DXS : [i64; 4] = [0,0,1,-1];
#[allow(dead_code)]
const DYS : [i64; 4]  = [1,-1,0,0];
#[allow(dead_code)]
const INF : i64 = 999999999;

////////////////////////////////////////////////


fn make_cost(change_cost: &Vec<Vec<i64>>,color_map: &Vec<Vec<i64>>,n : usize) -> Vec<i64>{
    let c = change_cost.len();
    let mut ret = vec![0 as i64;c];
    //eprintln!("make-cost start");
    //eprintln!("n={},c={}",n,c);

    for i in 0..color_map.len(){
        for j in 0..color_map[0].len(){
            if (i+j)%3 == n{
                let color_from = (color_map[i][j]-1) as usize;
                
                for color_to in 0..c{
                    ret[color_to] += change_cost[color_from][color_to];
                }
            }
        }
    }
    //eprintln!("make-cost end");

    ret
}

fn solve(costs:Vec<Vec<i64>>)->i64{
    let c = costs[0].len();
    let mut min_val = 999999999999;

    for c1 in 0..c{
        for c2 in 0..c{
            if c1 == c2{
                continue;
            }

            for c3 in 0..c{
                if c1 == c3 || c2 == c3{
                    continue;
                }

                min_val = cmp::min(
                    min_val,
                    costs[0][c1] + costs[1][c2] + costs[2][c3]
                );

            }
        }
    }

    min_val

}

fn main(){
    let inputs = read_ints();
    let (n,c) = (inputs[0],inputs[1]);

    let change_cost : Vec<Vec<i64>> = (0..c)
        .map(|_| read_ints())
        .collect();
    let color_map : Vec<Vec<i64>> = (0..n)
        .map(|_| read_ints())
        .collect();
    
    let types_change_cost : Vec<Vec<i64>> =
        (0..3)
        .map(|n| make_cost(&change_cost,&color_map,n))
        .collect();

    println!("{}",solve(types_change_cost));
}