There is an H \times W grid (H vertical, W horizontal), where each square contains a lowercase English letter.
Specifically, the letter in the square at the i-th row and j-th column is equal to the j-th character in the string S_i.
Snuke can apply the following operation to this grid any number of times:
 - Choose two different rows and swap them. Or, choose two different columns and swap them.
Snuke wants this grid to be symmetric.
That is, for any 1 \leq i \leq H and 1 \leq j \leq W, the letter in the square at the i-th row and j-th column and the letter in the square at the (H + 1 - i)-th row and (W + 1 - j)-th column should be equal.
Determine if Snuke can achieve this objective.

-----Constraints-----
 - 1 \leq H \leq 12
 - 1 \leq W \leq 12
 - |S_i| = W
 - S_i consists of lowercase English letters.

-----Input-----
Input is given from Standard Input in the following format:
H W
S_1
S_2
:
S_H

-----Output-----
If Snuke can make the grid symmetric, print YES; if he cannot, print NO.

-----Sample Input-----
2 3
arc
rac

-----Sample Output-----
YES

If the second and third columns from the left are swapped, the grid becomes symmetric, as shown in the image below:

Difficulty: VERY_HARD

Solutions:
from collections import Counter
(n, m) = map(int, input().split())
grid = [list(input()) for i in range(n)]

def jc(a, b):
	l = len(a)
	used = [0] * l
	for i in range(l):
		if used[i]:
			continue
		for j in range(i + 1, l):
			if used[j]:
				continue
			if a[i] == b[j] and b[i] == a[j]:
				used[i] = 1
				used[j] = 1
				break
	if used.count(0) <= l % 2:
		return True
	else:
		return False

def judge(a):
	h = len(a)
	w = len(a[0])
	used = [0] * h
	for i in range(h):
		if used[i]:
			continue
		ci = Counter(a[i])
		for j in range(i + 1, h):
			if used[j]:
				continue
			cj = Counter(a[j])
			if ci == cj:
				if jc(a[i], a[j]):
					used[i] = 1
					used[j] = 1
					break
	if used.count(0) <= h % 2:
		return True
	else:
		return False
gt = list(zip(*grid))
if judge(grid) & judge(gt):
	print('YES')
else:
	print('NO')


def _3():
	from collections import defaultdict

	def can_pair(s1, s2):
		l = []
		for (c1, c2) in zip(s1, s2):
			c = sorted([c1, c2])
			if c in l:
				l.remove(c)
			else:
				l.append(c)
		if len(s1) % 2 == 0:
			return len(l) == 0
		else:
			if len(l) == 1:
				if l[0][0] == l[0][1]:
					return True
			return False

	def pair_graph(s1, s2):
		N = len(s1)
		G = np.zeros([N, N])
		for i in range(N):
			for j in range(i + 1, N):
				if s1[i] == s2[j] and s1[j] == s2[i]:
					G[i, j] = 1
					G[j, i] = 1
		return G
	import numpy as np
	(H, W) = list(map(int, input().split(' ')))
	S = []
	d = defaultdict(list)
	for h in range(H):
		s = input()
		S.append(s)
		d[''.join(sorted(S))].append(h)
	already_paired = np.zeros(H)
	Gs = []
	for i in range(H):
		if already_paired[i]:
			continue
		for j in range(i + 1, H):
			if already_paired[j]:
				continue
			if can_pair(S[i], S[j]):
				already_paired[i] = 1
				already_paired[j] = 1
				G = pair_graph(S[i], S[j])
				Gs.append(G)
				break
	if already_paired.sum() < H - 1:
		print('NO')
		return
	elif already_paired.sum() == H - 1:
		for i in range(H):
			if already_paired[i] == 0:
				G = pair_graph(S[i], S[i])
				Gs.append(G)
				break
	G = np.array(Gs).sum(axis=0) // len(Gs)

	def is_perfect_matching(G):
		N = len(G)
		if N == 1:
			return True
		for i in range(N):
			for j in range(i + 1, N):
				if G[i, j] == 1:
					l = list(range(N))
					l.remove(i)
					l.remove(j)
					if len(l) == 0:
						return True
					if is_perfect_matching(G[l][:, l]):
						return True
		return False
	if is_perfect_matching(G):
		print('YES')
	else:
		print('NO')

def __starting_point():
	_3()
__starting_point()


def check(field):
	tr = list(map(''.join, list(zip(*field))))
	paired = set()
	center = -1
	for (i, col1) in enumerate(tr):
		if i in paired:
			continue
		for (j, col2) in enumerate(tr[i + 1:], start=i + 1):
			if j in paired:
				continue
			if col1 == col2[::-1]:
				paired.add(i)
				paired.add(j)
				break
		else:
			if center == -1 and col1 == col1[::-1]:
				center = i
			else:
				return False
	return True

def arrange_row(field, new_field, i, remain):
	if len(remain) == 0:
		return check(new_field)
	j = remain.pop()
	new_field[i] = field[j]
	for k in list(remain):
		remain.remove(k)
		new_field[h - i - 1] = field[k]
		result = arrange_row(field, new_field, i + 1, remain)
		if result:
			return True
		remain.add(k)
	remain.add(j)
	return False

def solve(h, w, field):
	new_field = [None] * h
	remaining_row = set(range(h))
	if h % 2 == 0:
		return arrange_row(field, new_field, 0, remaining_row)
	for i in list(remaining_row):
		remaining_row.remove(i)
		new_field[h // 2] = field[i]
		result = arrange_row(field, new_field, 0, remaining_row)
		if result:
			return True
		remaining_row.add(i)
	return False
(h, w) = list(map(int, input().split()))
field = [input() for _ in range(h)]
print('YES' if solve(h, w, field) else 'NO')


import numpy as np
(H, W) = map(int, input().split())
S = list()
for _ in range(H):
	S.append(list(input()))
S_arr = np.array(S)
res = 'NO'

def check_col_switch(S_arr, H, W):
	if W % 2 == 1:
		res_bar = -1
	else:
		res_bar = 0
	done_col = np.zeros(W)
	for j in range(W):
		if done_col[j] == 1:
			continue
		rev_j = S_arr[::-1, j]
		for k in range(W):
			if np.prod(S_arr[:, k] == rev_j) == 1 and j != k and (done_col[k] == 0):
				done_col[j] = 1
				done_col[k] = 1
				break
		if done_col[j] == 0:
			if np.prod(S_arr[:, j] == rev_j) == 1:
				done_col[j] = 1
				res_bar += 1
			else:
				res_bar += 10
	if res_bar <= 0:
		return 'YES'
	else:
		return 'NO'

def check_col_switch_fast(S_arr, H, W):
	col_raw = np.array([''.join(list(S_arr[:, j])) for j in range(W)])
	col_reverse = np.array([''.join(list(S_arr[::-1, j])) for j in range(W)])
	argsa = np.argsort(col_raw)
	argsb = np.argsort(col_reverse)
	res = 'YES'
	for j in range(W):
		if col_raw[argsa[j]] != col_reverse[argsb[j]]:
			res = 'NO'
			break
	cnt_single = 0
	for j in range(W):
		if argsa[j] == argsb[j]:
			cnt_single += 1
	j = 0
	while j < W - 1:
		if col_raw[argsa[j]] != col_raw[argsa[j + 1]]:
			cnt_single -= 2
			j += 2
		else:
			j += 1
	if cnt_single >= 2:
		res = 'NO'
	return res

def make_pairs(x_list):
	if len(x_list) <= 2:
		return [[x_list]]
	else:
		res = []
		for j in range(1, len(x_list)):
			x_list_s = [x_list[k] for k in range(1, len(x_list)) if k != j]
			res = res + [[[x_list[0], x_list[j]]] + xl for xl in make_pairs(x_list_s)]
		if len(x_list) % 2 == 1:
			x_list_l = [x_list[k] for k in range(1, len(x_list))]
			res = res + [xl + [[x_list[0]]] for xl in make_pairs(x_list_l)]
		return res

def run_row_switch(S_arr, row_matching, H, W):
	S_arr_row = S_arr.copy()
	i = 0
	for mat in row_matching:
		if len(mat) == 2:
			S_arr_row[i, :] = S_arr[mat[0], :]
			S_arr_row[H - 1 - i, :] = S_arr[mat[1], :]
			i += 1
		else:
			S_arr_row[(H - 1) // 2, :] = S_arr[mat[0], :]
	return S_arr_row
row_match_list = make_pairs([i for i in range(H)])
same_row_list = []
for i in range(H):
	j_list = [i]
	for j in range(H):
		if i != j and np.prod(np.sort(S_arr[i, :]) == np.sort(S_arr[j, :])) == 1:
			j_list.append(j)
	same_row_list.append(j_list)

def pass_condition(rs):
	res = True
	for pair in rs:
		if len(pair) == 1:
			continue
		if pair[1] not in same_row_list[pair[0]]:
			res = False
			break
	return res
row_match_list_s = [rs for rs in row_match_list if pass_condition(rs)]
for rs in row_match_list_s:
	res = check_col_switch(run_row_switch(S_arr, rs, H, W), H, W)
	if res == 'YES':
		break
print(res)