Problem:
Score : 700 points

Problem Statement

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 1

2 3
arc
rac

Sample Output 1

YES

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

Sample Input 2

3 7
atcoder
regular
contest

Sample Output 2

NO

Sample Input 3

12 12
bimonigaloaf
faurwlkbleht
dexwimqxzxbb
lxdgyoifcxid
ydxiliocfdgx
nfoabgilamoi
ibxbdqmzxxwe
pqirylfrcrnf
wtehfkllbura
yfrnpflcrirq
wvcclwgiubrk
lkbrwgwuiccv

Sample Output 3

YES

Solution in C++14 (GCC 5.4.1) (judge verdict: Wrong Answer)

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>

#include <iomanip>

#include <algorithm>

#include <vector>

#include <stack>

#include <queue>

#include <cmath>

#include <set>

#include <map>

#include <string>

#include <numeric>

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include <iterator>

#include <cstring>

using namespace std;


const int INF = 10000000;

typedef pair<int, int> P;
typedef long long ll;
#define PB push_back
#define rep(i, a) for (int i = 0; i < a; i++)

//char maze[100][101];

int sx, sy;

int gx, gy;

int qqq;

//各座標までの最短距離

int d[100][100];


//移動方向のベクトル

int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };

int ans = 0;
pair<int, int> red[101], blue[101];

/*
//ユークリッドの互除法
ll gcd(ll x, ll y) {
	if (x < y) swap(x, y);
	if (y == 0) return x;
	return gcd(y, x%y);
}

int isPrime(int x) {
	int i;
	if (x < 2) return 0;
	else if (x == 2) return 1;
	if (x % 2 == 0) return 0;
	for (int i = 3; i*i <= x; i += 2)
		if (x%i == 0) return 0;
	return 1;
}

int v_find(std::vector<int> vec, int number) {
	auto itr = std::find(vec.begin(), vec.end(), number);
	if (itr != vec.end()) { // 発見できたとき
		return 1;
	}
	else { // 発見できなかったとき
		return 0;
	}
}

int ok = 1000; //解が存在する値
int ng = -1;   //解が存在しない値

ll BIG = 10000000000;

ll POW(ll a, ll b) {
	ll c = 1;
	for (int i = 0; i < b; ++i) {
		c *= a;
	}
	return c;
}

int Kaijou(int a) {
	if (a < 2) return 1;
	return a * Kaijou(a - 1);
}


ll aa[51];

pair<int, int> Sc[50];

int MOD = 1000000007;
int imos[200001];
int br[100000];
int grid[1001][1001];
ll bigdp[1099][1099];
int used[1000][1000];

//逆元の計算用(pは素数のときb=p-2で逆元)
ll calc(int a, int b, int p) {
	if (b == 0) return 1;
	if (b % 2 == 0) {
		ll d = calc(a, b/2,p);
		return (d*d) % p;
	}
	else {
		return (a*calc(a, b - 1, p)) % p;
	}
}

int h, w;
ll dp[1000][1000];

ll f(int a, int b) {
	if (dp[a][b]) return dp[a][b];
	ll m = 1;
	if (a) if(grid[a-1][b]>grid[a][b]) m =(m+f(a-1,b))%MOD;
	if (b) if (grid[a][b-1]>grid[a][b]) m =(m+ f(a, b - 1))%MOD;
	if (a != h - 1) if (grid[a + 1][b]>grid[a][b]) m =(m+ f(a + 1, b))%MOD;
	if (b != w - 1) if (grid[a][b+1]>grid[a][b])  m =(m+ f(a, b + 1))%MOD;
	dp[a][b] = m;
	return m;
}
*/

int main() {
	int h,w;
	cin >> h>>w;
	char s[13][13] = { { 0 } };
	int yoko[12][12] = {{ 0 }}, tate[12][12] = { { 0 } };
	for (int i = 0; i < h; ++i) {
		cin >> s[i];
		rep(j, w) {
			yoko[i][j] = (int)(s[i][j] - 97);
			tate[j][i] = (int)(s[i][j] - 97);
		}
	}
	rep(i, h) sort(yoko[i], yoko[i] + w);
	rep(i, w) sort(tate[i], tate[i] + h);
	int YOKO = 0,TATE=0;
	int yu[12] = { 0 }, tu[12] = { 0 };
	
	rep(i, h) {
		rep(j, h) {
			if (i != j&&yu[j]==0) {
				int flag = 1;
				rep(k, w) {
				if (yoko[i][k] != yoko[j][k]) {
					flag = 0;
					break;
				 }
				}
				if (flag) {
					YOKO++;
					yu[j] = 1;
					goto PO;
				}
			}
		}
	PO: continue;
	}
	
	rep(i, w) {
		rep(j, w) {
			if (i != j && tu[j] == 0) {
				int flag = 1;
				rep(k, h) {
					if (tate[i][k] != tate[j][k]) {
						flag = 0;
						break;
					}
				}
				if (flag) {
					TATE++;
					tu[j] = 1;
					goto YO;
				}
			}
		}
	YO: continue;
	}
	int ff = 0;
	if (h % 2 && w & 2 && YOKO == h - 1 && TATE == w - 1) {
		rep(i, h) {
			if (yu[i] == 0) {
				rep(j, w) {
					if (yoko[i][j] != yoko[i][w - 1 - j]) ff = 1;
				}
			}
		}
		rep(i, w) {
			if (tu[i] == 0) {
				rep(j, h) {
					if (tate[i][j] != tate[i][h - 1 - j]) ff = 1;
				}
			}
		}
	}
	if (!ff&&YOKO >= h - (h % 2) && TATE >= w - (w % 2)) cout << "YES" << endl;
	else cout << "NO" << endl;
	cin >> qqq;
	return 0;
}