#include <bits/stdc++.h>

using namespace std;

vector<bool> used;
vector<int> huidige_volgorde;

int nb_rows, nb_cols;

vector< vector<int> > volgordes;

void go(int nb_used, int curr_idx)
{
    if(nb_used+1==nb_rows)
    {
        huidige_volgorde.push_back(curr_idx);
        volgordes.push_back(huidige_volgorde);
        huidige_volgorde.pop_back();
        return;
    }
    for(int i=curr_idx+1; i<nb_rows; i++)
    {
        if(used[i]) continue;
        huidige_volgorde.push_back(curr_idx);
        huidige_volgorde.push_back(i);
        used[curr_idx]=used[i]=true;
        int nxt=-1;
        for(int j=curr_idx+1; j<nb_rows; j++)
        {
            if(!used[j])
            {
                nxt=j;
                break;
            }
        }
        if(nxt==-1)
        {
            /*for(auto x : huidige_volgorde)
            {
                cerr << x << " ";
            }
            cerr << endl;*/
            volgordes.push_back(huidige_volgorde);
        }
        else
        {
            go(nb_used+2, nxt);
        }
        huidige_volgorde.pop_back();
        huidige_volgorde.pop_back();
        used[i]=used[curr_idx]=false;
    }
}

bool is_palin(string s)
{
    bool ret=true;
    for(int i=0; i<s.size(); i++)
    {
        if(s[i] != s[s.size()-1-i]) ret=false;
    }
    return ret;
}

void go2(int nb_used, int curr_idx, int unmatched)
{
    if(nb_used+1==nb_rows)
    {
        huidige_volgorde.push_back(unmatched);
        volgordes.push_back(huidige_volgorde);
        huidige_volgorde.pop_back();
        return;
    }
    for(int i=curr_idx+1; i<nb_rows; i++)
    {
        if(used[i] || i==unmatched) continue;
        huidige_volgorde.push_back(curr_idx);
        huidige_volgorde.push_back(i);
        used[curr_idx]=used[i]=true;
        int nxt=-1;
        for(int j=0; j<nb_rows; j++)
        {
            if(used[j]) continue;
            if(nb_used+3==nb_rows)
            {
                nxt=j;
                break;
            }
            else
            {
                if(j != unmatched)
                {
                    nxt=j;
                    break;
                }
            }
        }
        go2(nb_used+2, nxt, unmatched);
        huidige_volgorde.pop_back();
        huidige_volgorde.pop_back();
        used[i]=used[curr_idx]=false;
    }
}

int main()
{
    //freopen("inp.in", "r", stdin);
    scanf("%d %d", &nb_rows, &nb_cols);
    vector< vector<char> > original_grid(nb_rows, vector<char>(nb_cols));
    for(int i=0; i<nb_rows; i++)
    {
        for(int j=0; j<nb_cols; j++)
        {
            scanf(" %c", &original_grid[i][j]);
        }
    }
    used.assign(nb_rows, false);
    if(nb_rows%2==0) go(0,0);
    else
    {
        for(int i=0; i<nb_rows; i++)
        {
            if(i==0) go2(0,1,i);
            else go2(0,0,i);
        }
    }
    /*for(auto v : volgordes)
    {
        for(auto x : v)
        {
            cerr << x << " ";
        }
        cerr << endl;
    }*/
    cerr << volgordes.size() << endl;
    bool solution_found=false;
    for(vector<int> v : volgordes)
    {
        vector<string> woorden;
        for(int j=0; j<nb_cols; j++)
        {
            string s="";
            for(int i=0; i<nb_rows; i++) s+="X";
            for(int i=0; i<v.size(); i+=2)
            {
                s[i/2]=original_grid[v[i]][j];
            }
            for(int i=1; i<v.size(); i+=2)
            {
                s[nb_rows-1-(i/2)]=original_grid[v[i]][j];
            }
            woorden.push_back(s);
        }
        vector< vector<int> > graph(nb_cols);
        for(int i=0; i<nb_cols; i++)
        {
            for(int j=0; j<nb_cols; j++)
            {
                if(i==j) continue;
                bool ok=true;
                for(int k=0; k<woorden[i].size() && ok; k++)
                {
                    if(woorden[i][k] != woorden[j][woorden[j].size()-1-k]) ok=false;
                }
                if(ok) graph[i].push_back(j);
            }
        }
        vector<bool> vis(nb_cols, false);
        int nb_same=0;
        int nb_exactly_one_more=0;
        int nb_other=0;
        int palin_idx=-1;
        for(int i=0; i<nb_cols; i++)
        {
            if(vis[i]) continue;
            queue<int> q;
            vis[i]=true;
            q.push(i);
            vector<int> comp;
            comp.push_back(i);
            vector<int> color(nb_cols, -1);
            color[i]=0;
            while(!q.empty())
            {
                int now = q.front();
                q.pop();
                for(int neigh : graph[now])
                {
                    if(vis[neigh]) continue;
                    vis[neigh]=true;
                    color[neigh]=1-color[now];
                    q.push(neigh);
                    comp.push_back(neigh);
                }
            }
            int sz=comp.size();
            if(is_palin(woorden[i]))
            {
                if(sz&1)
                {
                    nb_exactly_one_more++;
                    palin_idx=i;
                }
                else nb_same++;
                continue;
            }
            else
            {
                int A=0;
                int B=0;
                for(int j=0; j<nb_cols; j++)
                {
                    if(color[j]==0) A++;
                    else if(color[j]==1) B++;
                }
                if(A==B) nb_same++;
                else if(abs(A-B)==1) nb_exactly_one_more++;
                else nb_other++;
            }
        }
        bool volgorde_ok=false;
        if(nb_other==0)
        {
            if(nb_cols%2==0)
            {
                if(nb_exactly_one_more==0) volgorde_ok=true;
            }
            else
            {
                if(nb_exactly_one_more==1 && palin_idx!=-1) volgorde_ok=true;
            }
        }
        if(volgorde_ok) solution_found=true;
    }
    if(solution_found)
    {
        printf("YES\n");
    }
    else
    {
        printf("NO\n");
    }
    return 0;
}


Measured memory_bytes: 1152