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 Kotlin (1.0.0) (judge verdict: Wrong Answer)


fun main(args:Array<String>):Unit {
    val (h: Int, w: Int) = readLine()!!.split(' ').map(String::toInt)
    val strings = (1 .. h).map{readLine()!!.toCharArray()}.toTypedArray()
    val rows = Array<AlphabetSummary>(h,{AlphabetSummary()})
    val columns = Array<AlphabetSummary>(w, {AlphabetSummary()})
    for (row in 0 until h){
        for (column in 0 until w){
            ++rows[row][strings[row][column]]
            ++columns[column][strings[row][column]]
        }
    }
    val rowsSorted = rows.sorted()
    val columnsSorted = columns.sorted()
    var canMake:Boolean = true
    var rowMid:AlphabetSummary? = null
    var columnMid:AlphabetSummary? = null
    if (h % 2 == 1){
        if (rows.count(AlphabetSummary::isPalindromable) % 2 != 1) canMake = false
        else {
            var usePalindrome = false
            var idx = 0
            while (idx < h){
                if (idx == h - 1){
                    if (!rowsSorted[idx].isPalindromable() || usePalindrome) canMake = false
                    ++idx
                }else if (rowsSorted[idx] != rowsSorted[idx + 1]){
                    if (rowsSorted[idx].isPalindromable() && !usePalindrome){
                        usePalindrome = true
                        rowMid = rowsSorted[idx]
                    }else{
                        canMake = false
                    }
                    ++idx
                }else idx += 2
            }
        }
    }else{
        for (idx in 0 until h step 2){
            if (rowsSorted[idx] != rowsSorted[idx + 1]) canMake = false
        }
    }
    if (w % 2 == 1){
        if (columns.count(AlphabetSummary::isPalindromable) % 2 != 1) canMake = false
        else{
            var usePalindrome = false
            var idx = 0
            while (idx < w){
                if (idx == w - 1){
                    if (!columnsSorted[idx].isPalindromable() || usePalindrome) canMake = false
                    ++idx
                }else if (columnsSorted[idx] != columnsSorted[idx + 1]){
                    if (columnsSorted[idx].isPalindromable() && !usePalindrome){
                        usePalindrome = true
                        columnMid = columnsSorted[idx]
                        if (h % 2 == 1 && w % 2 == 1){
                            if (('a'..'z').filter { rowMid!![it] % 2 == 1}.filter { columnMid!![it] % 2 == 1}.count() == 0) canMake = false
                        }
                    }else{
                        canMake = false
                    }
                    ++idx
                }else idx += 2
            }
        }
    }else {
        for (idx in 0 until w step 2){
            if (columnsSorted[idx] != columnsSorted[idx + 1]) canMake = false
        }
    }
    println(if (canMake) "YES" else "NO")
}
fun AlphabetSummary.isPalindromable():Boolean{
    if (this.count % 2 == 0){
        for (char in 'a' .. 'z'){
            if (this[char] % 2 != 0) return false
        }
        return true
    }else{
        var hasOdd = false
        for (char in 'a' .. 'z'){
            if (this[char] % 2 != 0){
                if (hasOdd) return false
                else hasOdd = true
            }
        }
        return hasOdd
    }
}
class AlphabetSummary: Comparable<AlphabetSummary>{
    private val summary = Array<Int>(26, {0})
    var count:Int = 0
        get
        private set

    operator fun get(char:Char):Int {
        ++count
        return summary[char.toInt() - 'a'.toInt()]
    }
    operator fun set(char:Char, value:Int){
        summary[char.toInt() - 'a'.toInt()] = value
    }

    override fun equals(other: Any?): Boolean {
        if (other is AlphabetSummary) {
            for (idx in 0..25) {
                if (summary[idx] != other.summary[idx]) return false
            }
            return true
        }else{
            return false
        }
    }

    override operator fun compareTo(other:AlphabetSummary):Int {
        for (idx in 0 .. 25){
            if (summary[idx] != other.summary[idx]) return summary[idx].compareTo(other.summary[idx])
        }
        return 0
    }
}