use proconio::input;

fn generate_even_pairings(n: usize) -> Vec<Vec<(usize, usize)>> {
    assert!(n % 2 == 0);

    fn dfs(ckd: &mut [bool], now: &mut Vec<(usize, usize)>, ans: &mut Vec<Vec<(usize, usize)>>) {
        if 2 * now.len() == ckd.len() {
            ans.push(now.clone());
            return;
        }
        let i = ckd
            .iter()
            .copied()
            .enumerate()
            .find(|&(_, b)| !b)
            .unwrap()
            .0;
        ckd[i] = true;
        for j in 0..ckd.len() {
            if ckd[j] {
                continue;
            }
            ckd[j] = true;
            now.push((i, j));
            dfs(ckd, now, ans);
            now.pop();
            ckd[j] = false;
        }
        ckd[i] = false;
    }

    let mut ckd = vec![false; n];
    let mut now = vec![];
    let mut ans = vec![];

    dfs(&mut ckd, &mut now, &mut ans);

    ans
}

fn convert_to_permutation(pairs: Vec<(usize, usize)>) -> Vec<usize> {
    let n = pairs.len() * 2;
    let mut seq = vec![0; n];
    for (i, (x, y)) in pairs.into_iter().enumerate() {
        seq[i] = x;
        seq[n - 1 - i] = y;
    }
    seq
}

fn generate_representitve_parmutations(n: usize) -> Vec<Vec<usize>> {
    if n % 2 == 0 {
        generate_even_pairings(n)
            .into_iter()
            .map(convert_to_permutation)
            .collect()
    } else {
        (0..n)
            .map(|center| {
                generate_even_pairings(n - 1)
                    .into_iter()
                    .map(convert_to_permutation)
                    .map(move |mut seq| {
                        for x in &mut seq {
                            if center <= *x {
                                *x += 1;
                            }
                        }
                        seq.insert(n / 2, center);
                        seq
                    })
            })
            .flatten()
            .collect()
    }
}

fn main() {
    input!(h: usize, w: usize, v: [proconio::marker::Chars; h]);
    let ans = generate_representitve_parmutations(w).iter().any(|seq| {
        let mut v: Vec<Vec<char>> = v
            .iter()
            .map(|s| {
                let mut ret = vec!['$'; w];
                for (i, &x) in seq.iter().enumerate() {
                    ret[i] = s[x];
                }
                ret
            })
            .collect();

        loop {
            if v.len() <= 1 {
                return v.is_empty() || v[0] == v[0].iter().copied().rev().collect::<Vec<char>>();
            }
            if let Some((i, j)) = (0..v.len())
                .map(|i| {
                    let s = &v[i];
                    let t: &Vec<_> = &s.iter().copied().rev().collect();
                    if let Some(j) = v
                        .iter()
                        .enumerate()
                        .skip(i + 1)
                        .find(|&(_, u)| t == u)
                        .map(|p| p.0)
                    {
                        Some((i, j))
                    } else {
                        None
                    }
                })
                .filter_map(std::convert::identity)
                .next()
            {
                assert!(i < j);
                v.remove(j);
                v.remove(i);
            } else {
                return false;
            }
        }
    });
    println!("{}", if ans { "YES" } else { "NO" });
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_generate_representitive_permutations_zero() {
        let expected = vec![Vec::<usize>::new()];
        let result = generate_representitve_parmutations(0);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_representitive_permutations_one() {
        let expected = vec![vec![0]];
        let result = generate_representitve_parmutations(1);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_representitive_permutations_two() {
        let expected = vec![vec![0, 1]];
        let result = generate_representitve_parmutations(2);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_representitive_permutations_three() {
        let expected = vec![vec![1, 0, 2], vec![0, 1, 2], vec![0, 2, 1]];
        let result = generate_representitve_parmutations(3);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_representitive_permutations_four() {
        let expected = vec![vec![0, 2, 3, 1], vec![0, 1, 3, 2], vec![0, 1, 2, 3]];
        let result = generate_representitve_parmutations(4);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_representitive_permutations_five() {
        let result = generate_representitve_parmutations(5);
        println!("{:?}", &result);
        assert_eq!(15, result.len());
    }

    #[test]
    fn test_generate_representitive_permutations_six() {
        let result = generate_representitve_parmutations(6);
        println!("{:?}", &result);
        assert_eq!(15, result.len());
    }

    #[test]
    fn test_generate_even_pairs_zero() {
        let expected = vec![Vec::<(usize, usize)>::new()];
        let result = generate_even_pairings(0);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_even_pairs_two() {
        let expected = vec![vec![(0, 1)]];
        let result = generate_even_pairings(2);
        assert_eq!(expected, result);
    }

    #[test]
    fn test_generate_even_pairs_four() {
        let expected = vec![
            vec![(0, 1), (2, 3)],
            vec![(0, 2), (1, 3)],
            vec![(0, 3), (1, 2)],
        ];
        let result = generate_even_pairings(4);
        assert_eq!(expected, result);
    }
}


Measured memory_bytes: 4232