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 Java8 (OpenJDK 1.8.0) (judge verdict: Runtime Error)

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

class Main{

    static long[] hash;

    static int[] used;
    static int[][] tmp;
    static int[][] mat;
    static int H,W;
    static boolean ans=false;
    static long mod = (long)1e9+7;
    static long base = 9973;



    static void check(){
        if(ans)return;
        for(int i=0;i<H;++i){
            if(used[i]%2==0){
                tmp[used[i]/2]=mat[i];
            }else{
                tmp[H-1 -used[i]/2]=mat[i];
            }
        }
        Set<Long> usedHash = new HashSet<>();
        for(int i=0;i<W;++i){
            long hsh = 0;
            for(int j=0;j<H;++j)hsh = (hsh*base + tmp[j][i])%mod;
            if(!usedHash.remove(hsh)){
                hsh = 0;
                for(int j=H-1;j>=0;--j)hsh = (hsh*base + tmp[j][i])%mod;
                usedHash.add(hsh);
            }
        }
        if(usedHash.size()==0)ans = true;
        if(usedHash.size()==1){
            for(int i=0;i<W;++i){
                long hsh = 0;
                for(int j=H-1;j>=0;--j)hsh = (hsh*base + tmp[j][i])%mod;
                if(usedHash.contains(hsh)){
                    for(int k=0; k<(H-1-k);++k)if(tmp[k][i]!=tmp[H-1-k][i])return;
                    ans = true;
                    return;
                }
            }
        }
    }

    static void dfs(int v, int depth){
        if(v==-1){
            boolean full=true;
            for(int i=0;i<H;++i)if(used[i]<0){
                full=false;
                used[i]=depth;
                dfs(i,depth+1);
                used[i]=-1;
            }
            if(full)check();
        }else{
            for(int i=0;i<H;++i){
                if(i==v)continue;
                if(hash[i]==hash[v]){
                    used[i]=depth;
                    dfs(-1,depth+1);
                    used[i]=-1;
                }
            }
        }
    }

    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        H = scan.nextInt();
        W = scan.nextInt();
        mat = new int[H][W];
        tmp = new int[H][W];
        hash = new long[H];
        used = new int[H];
        Arrays.fill(used,-1);
        for(int i=0;i<H;++i){
            String s = scan.next();
            int cnt[] = new int[26];
            for(int j=0;j<W;++j){
                mat[i][j]=s.charAt(j)-'a';
                cnt[mat[i][j]]++;
            }
            for(int j=0;j<26;++j)hash[i] = (hash[i]*base + cnt[j])%mod;
        }
        dfs(-1,0);
        if(ans)System.out.println("YES");
        else System.out.println("NO");
    }
}