#include <iostream>
#include <set>
#include <string>
#include <random>
#include <unordered_map>
#include <vector>
using namespace std;

int main(){
    int N, M;
    cin >> N >> M;
    set<string> Set;
    unordered_map<string, int> count;
    unordered_map<string, bool> done;
    int Lmin = 10000, Lmax = 0;
    while(M--){
        string S;
        cin >> S;
        Set.insert(S);
        done[S] = true;
        Lmin = min(Lmin, (int)S.size());
        Lmax = max(Lmax, (int)S.size());
    }
    for(string S : Set){
        for(int k = 0; k < S.size(); k++){
            for(int l = 1; k + l <= S.size(); l++){
                count[S] += done[S.substr(k, l)];
            }
        }
    }
    for(auto [key, val] : count){
        if(key.size() != Lmin){
            count[key] = 0;
            Set.erase(key);
        }
    }
    string ans[N];
    for(int i = 0; i < N; i++){
        string last;
        int m = 0;
        for(auto [key, val] : count){
            if(m < val){
                m = val;
                last = key;
            }
        }
        ans[i] = "";
        int cnt = 0;
        while(true){
            bool finish = true;
            for(int j = 0; j < last.size(); j++){
                string temp = last.substr(j);
                string temp_next = temp;
                temp_next.back()++;
                if(Set.lower_bound(temp) != Set.lower_bound(temp_next)){
                    string in = *Set.lower_bound(temp);
                    if(cnt == 0){
                        finish = false;
                        cnt += in.size();
                        ans[i] = ans[i] + in;
                    }else{
                        int start = last.size() - j;
                        int arg = in.size() - start;
                        if(cnt + arg > N + 30){
                            finish = true;
                            break;
                        }
                        for(int k = start; k < in.size(); k++){
                            ans[i].push_back(in[k]);
                            cnt++;
                        }
                        finish = false;
                    }
                    last = in;
                    for(int k = 0; k < last.size(); k++){
                        for(int l = 1; k + l <= last.size(); l++){
                            Set.erase(last.substr(k, l));
                            count[last.substr(k, l)] = 0;
                        }
                    }
                    break;
                }
            }
            if(finish) break;
        }
        for(int j = ans[i].size(); j < N; j++) ans[i].push_back('A' + (rand() % 8));
    }
    for(int i = 0; i < N; i++){
        int r = rand();
        ans[i].resize(N);
        for(int j = 0; j < N; j++){
            cout << ans[i][(j + r) % N];
        }
        cout << endl;
    }
    return 0;
}
/*
    /\ In The Name Of Allah /\
    Author : Jawahiir Nabhan
*/
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const char nl = '\n';
const int NM = 3e6 + 10;

ll dp[4][NM];
int main()
{
    ll N,K; cin>> N >> K;
    dp[0][0] = 1;

    for (ll i = 0; i < 3; i++) {
        for (ll j = 0; j < 3 * N; j++){
           dp[i + 1][j + 1] += dp[i][j];
           if (j + N + 1 <= NM) dp[i + 1][j + N + 1] -= dp[i][j];
        }
        for (int j = 1; j <= 3 * N; j++) {
           dp[i + 1][j] += dp[i + 1][j - 1];
        }
    }

    ll S = 3;
    while(K > dp[3][S]){
        K -= dp[3][S];
        S++;
    }
    // S -> Sum of BTP of the K-th position.

    ll X = 1;
    while(K > dp[2][S - X]){
        K -= dp[2][S - X];
        X++;
    }

    ll Y = max(1ll, S - X - N) + K - 1;
    ll Z = S - X - Y;
    cout<< X << ' ' << Y << ' ' << Z << nl;
}
