Buggy python submission (verdict: Time Limit Exceeded):
def iin(): return int(input())
def nl(): return list(map(int, input().split()))
def ary(r, c, v): return [[v for _ in range(c)] for _ in range(r)]

N, C = nl()
d = [nl() for _ in range(C)]
c = [nl() for _ in range(N)]

ans = float('inf')
for c0 in range(1, C + 1):
    for c1 in range(1, C + 1):
        if c0 == c1:
            continue
        for c2 in range(1, C + 1):
            if c0 == c2 or c1 == c2:
                continue
            cost = 0
            for i in range(N):
                for j in range(N):
                    next_color = [c0, c1, c2][(i + j) % 3]
                    cost += d[c[i][j] - 1][next_color - 1]
            ans = min(ans, cost)
print(ans)

Fixed submission:
n, c = map(int, input().split())
arrD = list(list(map(int, input().split())) for i in range(c))
arrC = list(list(map(int, input().split())) for i in range(n))

##剰余r=0,1,2で、
    ##色の出現数を確認する -> いずれかの色に統一する
        ##どの色に統一するか全パターンを実施して、違和感を算出
##和を取る

arrCCnt = []
for r in range(3):
    d = dict()
    for i in range(1, c + 1):
        d[i] = 0
    arrCCnt += [d]

ret = 1000 * 500 * 500
for r in range(3):
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if (i + j) % 3 == r:
                arrCCnt[r][arrC[i - 1][j - 1]] += 1##色の出現数を確認

##print(arrCCnt)
for c0 in range(1, c + 1):
    for c1 in range(1, c + 1):
        for c2 in range(1, c + 1):
            if c0 != c1 and c1 != c2 and c2 != c0:
                buf = 0
                ##print(c0,c1,c2)
                for i0 in range(1, c + 1):
                    ##print(i0)
                    buf += arrD[i0 - 1][c0 - 1] * arrCCnt[0][i0]##数
                for i1 in range(1, c + 1):
                    buf += arrD[i1 - 1][c1 - 1] * arrCCnt[1][i1]##数
                for i2 in range(1, c + 1):
                    buf += arrD[i2 - 1][c2 - 1] * arrCCnt[2][i2]##数
                ret = min(ret, buf)
print(ret)

Buggy python submission (verdict: Time Limit Exceeded):
lngN, lngC = map(int, input().split())

##  lstD[x][y]
##  1 オリジン の C × C グリッド として扱うために、[False] * lngC を第一行と第一列に追加
##  x -> y に塗り替えたときの違和感
##  x, y: 0 ... lngC - 1
lstD = []
lstD.append([False] * lngC)
for i in range(lngC):
    lstD.append([False] + list(map(int, input().split())))
##  lstC[i][j]
##  1 オリジン の N × N グリッド として扱うために、[False] * lngN を第一行と第一列に追加
##  マス(i, j)の初期色
##  1 から C までの値を取る
lstC = []
lstC.append([False] * lngN)
for i in range(lngN):
    lstC.append([False] + list(map(int, input().split())))
##  lstDSum[r][c]
##  剰余 r のグループを 色 c で塗るときの違和感の和
##　[c]を 1 オリジン として扱うために、[False] * lngC を第一行に追加
##  r: 0, 1, 2
##  c: 1 ... lngC
lstDSum = [False] * 3
for r in range(3):
    lstDSum[r] = [False] * (lngC + 1)
    for c in range(1, lngC + 1):
        lstDSum[r][c] = 0##違和感の初期値

for i in range(1, lngN + 1):
    for j in range(1, lngN + 1):
        for c in range(1, lngC + 1):
            r = (i + j) % 3##　剰余
            oriC = lstC[i][j]##初期色
            lstDSum[r][c] += lstD[oriC][c]

ans = float('inf')
for i in range(1, lngC + 1):
    for j in range(1, lngC + 1):
        if (i != j):
            for k in range(1, lngC + 1):
                if (i != k) and (j != k):
                    ans = min(ans, lstDSum[0][i] + lstDSum[1][j] + lstDSum[2][k])
print(ans)

##グリッドのマス(i, j)とすると,
##(i + j) % 3 の値によって, マスは 3 グループに分かれる (0, 1, 2)

##各グループの色分けの仕方は, itertools.permutations(c, 3) 通り
##内訳は次の通り
    ##(0)色 1 から C までの C 通りに色分け
    ##(1)色 1 から C までの (C - 1) 通りに色分け ((0) 分を除外)
    ##(2)色 1 から C までの (C - 2) 通りに色分け ((0, 1) 分を除外)

##各グループについて
##色 1 から C までの C 通りに色分けしたときの違和感の和を配列化
##lstDSum[グループ番号][色]
    ##グループ番号: 0, 1, 2
    ##色: 1 から C まで

##for 文で, 各グループを塗る色を全探索
##(グループ番号, 色) = (0, i), (1, j), (2, k)とするときの違和感の和
##lstDSum[0][i] + lstDSum[1][j] + lstDSum[2][k]
##これの最小値を取ればよい


Fixed submission:
n, c = map(int, input().split())
arrD = list(list(map(int, input().split())) for i in range(c))
arrC = list(list(map(int, input().split())) for i in range(n))

##剰余r=0,1,2で、
    ##色の出現数を確認する -> いずれかの色に統一する
        ##どの色に統一するか全パターンを実施して、違和感を算出
##和を取る

arrCCnt = []
for r in range(3):
    d = dict()
    for i in range(1, c + 1):
        d[i] = 0
    arrCCnt += [d]

ret = 1000 * 500 * 500
for r in range(3):
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if (i + j) % 3 == r:
                arrCCnt[r][arrC[i - 1][j - 1]] += 1##色の出現数を確認

##print(arrCCnt)
for c0 in range(1, c + 1):
    for c1 in range(1, c + 1):
        for c2 in range(1, c + 1):
            if c0 != c1 and c1 != c2 and c2 != c0:
                buf = 0
                ##print(c0,c1,c2)
                for i0 in range(1, c + 1):
                    ##print(i0)
                    buf += arrD[i0 - 1][c0 - 1] * arrCCnt[0][i0]##数
                for i1 in range(1, c + 1):
                    buf += arrD[i1 - 1][c1 - 1] * arrCCnt[1][i1]##数
                for i2 in range(1, c + 1):
                    buf += arrD[i2 - 1][c2 - 1] * arrCCnt[2][i2]##数
                ret = min(ret, buf)
print(ret)

Buggy python submission (verdict: Time Limit Exceeded):
lngN, lngC = map(int, input().split())

##  lstD[x][y]
##  C×C
##  x -> y に塗り替えたときの違和感
##  x, y: 0 ... lngC - 1
##  x == y: 0
##  x != y: 1 から 1000 の値を取る
lstD = []
for i in range(lngC):
    lstD.append(list(map(int, input().split())))
##  lstC[i][j]
##  N×N
##  マス(i, j)の初期色
##  1 から C までの値を取る
lstC = []
for i in range(lngN):
    lstC.append(list(map(int, input().split())))
##  lstDSum[r][c]
##  剰余 r のグループを 色 c で塗るときの違和感の和
##  r: 0, 1, 2
##  c: 1 ... lngC
lstDSum = dict()
for r in range(3):
    lstDSum[r] = dict()
    for c in range(1, lngC + 1):
        lstDSum[r][c] = 0##違和感の初期値

for i in range(lngN):
    for j in range(lngN):
        for c in range(1, lngC + 1):
            ##　剰余
            ##　配列は 0 オリジンで, グリッドは 1 オリジンなので,
            ##　配列の座標 i, j から グリッドの座標に変換するために, i, j に 1 足した（意味はない）
            r = ((i + 1) + (j + 1)) % 3
            oriC = lstC[i][j]##初期色
            ##　lstD[初期色][塗り替えた後の色] で 色は, 0 ... lngC - 1までの値を取る
            ##　oriC, cは共に 1 ... lngC までの値を取るので, 1 減らす必要がある
            lstDSum[r][c] += lstD[oriC - 1][c - 1]            

ans = float('inf')
for i in range(1, lngC + 1):
    for j in range(1, lngC + 1):
        if (i != j):
            for k in range(1, lngC + 1):
                if (i != k) and (j != k):
                    ans = min(ans, lstDSum[0][i] + lstDSum[1][j] + lstDSum[2][k])
print(ans)

##グリッドのマス(i, j)とすると,
##(i + j) % 3 の値によって, マスは 3 グループに分かれる (0, 1, 2)

##各グループの色分けの仕方は, itertools.permutations(c, 3) 通り
##内訳は次の通り
    ##(0)色 1 から C までの C 通りに色分け
    ##(1)色 1 から C までの (C - 1) 通りに色分け ((0) 分を除外)
    ##(2)色 1 から C までの (C - 2) 通りに色分け ((0, 1) 分を除外)

##各グループについて
##色 1 から C までの C 通りに色分けしたときの違和感の和を配列化
##lstDSum[グループ番号][色]
    ##グループ番号: 0, 1, 2
    ##色: 1 から C まで

##for 文で, 各グループを塗る色を全探索
##(グループ番号, 色) = (0, i), (1, j), (2, k)とするときの違和感の和
##lstDSum[0][i] + lstDSum[1][j] + lstDSum[2][k]
##これの最小値を取ればよい


Fixed submission:
n, c = map(int, input().split())
arrD = list(list(map(int, input().split())) for i in range(c))
arrC = list(list(map(int, input().split())) for i in range(n))

##剰余r=0,1,2で、
    ##色の出現数を確認する -> いずれかの色に統一する
        ##どの色に統一するか全パターンを実施して、違和感を算出
##和を取る

arrCCnt = []
for r in range(3):
    d = dict()
    for i in range(1, c + 1):
        d[i] = 0
    arrCCnt += [d]

ret = 1000 * 500 * 500
for r in range(3):
    for i in range(1, n + 1):
        for j in range(1, n + 1):
            if (i + j) % 3 == r:
                arrCCnt[r][arrC[i - 1][j - 1]] += 1##色の出現数を確認

##print(arrCCnt)
for c0 in range(1, c + 1):
    for c1 in range(1, c + 1):
        for c2 in range(1, c + 1):
            if c0 != c1 and c1 != c2 and c2 != c0:
                buf = 0
                ##print(c0,c1,c2)
                for i0 in range(1, c + 1):
                    ##print(i0)
                    buf += arrD[i0 - 1][c0 - 1] * arrCCnt[0][i0]##数
                for i1 in range(1, c + 1):
                    buf += arrD[i1 - 1][c1 - 1] * arrCCnt[1][i1]##数
                for i2 in range(1, c + 1):
                    buf += arrD[i2 - 1][c2 - 1] * arrCCnt[2][i2]##数
                ret = min(ret, buf)
print(ret)