#include <bits/stdc++.h>
using namespace std;
 
static const int INF = 1e9;
 
int n, m;
vector<string> A;          // đầu vào
vector<string> B;          // kết quả (ban đầu = A)
 
// cnt[col][digit][i] = số hàng <= i có chữ số 'digit' ở cột col
// i chạy 0..n, trong đó i=0 là 0 phần tử.
vector<array<vector<int>,10>> cnt;
 
// số cột tối thiểu cần để tách L phần tử (cơ số 10)
int needCols[105];
 
inline int blockCost(int col, int L, int R, int d){
    // số hàng trong [L..R] KHÔNG phải d = (R-L+1) - (# d)
    int have = cnt[col][d][R+1] - cnt[col][d][L];
    return (R - L + 1) - have;
}
 
// dp[col][L][R] = chi phí tối thiểu solve(col, L, R)
// -1 nghĩa là chưa tính, >=0 là đã có; INF là không khả thi
static int dp[401][105][105];
 
// Lưu cách chia khối cho state (col,L,R): vector of (endIndex, digit)
// Các khối liên tiếp từ pos -> end với chữ số digit ở cột col
struct Key {
    int col,L,R;
    bool operator==(Key const& o) const { return col==o.col && L==o.L && R==o.R; }
};
struct KeyHash {
    size_t operator()(Key const& k) const {
        return (k.col*1315423911u) ^ (k.L*2654435761u) ^ (k.R*97531u);
    }
};
unordered_map<size_t, vector<pair<int,int>>> choiceMap;
inline size_t packKey(int col,int L,int R){
    // đóng gói key gọn gàng
    return ( (size_t)col << 14 ) ^ ( (size_t)L << 7 ) ^ (size_t)R;
}
 
// forward khai báo
int solve(int col, int L, int R);
 
int solve(int col, int L, int R){
    if (L==R) return 0;
    if (col >= m) return INF;
 
    if (dp[col][L][R] != -1) return dp[col][L][R];
 
    int len = R - L + 1;
    int remain = m - col;
    if (needCols[len] > remain) return dp[col][L][R] = INF;
 
    // Quy hoạch động cục bộ để chia khối ở cột 'col' với chữ số tăng chặt
    // go(pos, last_d): chi phí nhỏ nhất để phủ [pos..R], với chữ số của khối kế tiếp > last_d
    // Lưu vết để dựng các khối
    vector<array<int,11>> memo(R+2 - L);           // 11 giá trị last_d: -1..9 -> chỉ số +1
    vector<array<int,11>> takeEnd(R+2 - L);
    vector<array<int,11>> takeDigit(R+2 - L);
    for (auto &row : memo) row.fill(-2); // -2 = chưa tính
 
    function<int(int,int)> go = [&](int pos, int lastdIdx)->int{
        // lastdIdx: ánh xạ -1..9 -> 0..10 ; last_digit = lastdIdx-1
        if (pos > R) return 0;
        int &ret = memo[pos - L][lastdIdx];
        if (ret != -2) return ret;
        ret = INF; takeEnd[pos - L][lastdIdx] = -1; takeDigit[pos - L][lastdIdx] = -1;
 
        int last_d = lastdIdx - 1;
        for (int d = last_d + 1; d <= 9; ++d){
            // Chọn chữ số của KHỐI hiện tại là d, chọn điểm kết thúc khối j (pos..R)
            for (int j = pos; j <= R; ++j){
                int c1 = blockCost(col, pos, j, d);
                int c2 = solve(col+1, pos, j);
                if (c2 >= INF) continue; // không khả thi
int c3 = go(j+1, d+1); // next lastdIdx = d+1
                if (c1 + c2 + c3 < ret){
                    ret = c1 + c2 + c3;
                    takeEnd[pos - L][lastdIdx] = j;
                    takeDigit[pos - L][lastdIdx] = d;
                }
            }
        }
        return ret;
    };
 
    int best = go(L, 0); // last_d = -1 -> idx = 0
    dp[col][L][R] = best;
    if (best >= INF) return best;
 
    // Lưu cách chia khối để dựng lời giải
    vector<pair<int,int>> blocks;
    int pos = L, lastIdx = 0;
    while (pos <= R){
        int j = takeEnd[pos - L][lastIdx];
        int d = takeDigit[pos - L][lastIdx];
        blocks.push_back({j, d});
        lastIdx = d + 1;
        pos = j + 1;
    }
    choiceMap[packKey(col,L,R)] = move(blocks);
    return best;
}
 
void buildSolution(int col, int L, int R){
    if (L==R || col>=m) return;
    auto it = choiceMap.find(packKey(col,L,R));
    if (it == choiceMap.end()) return; // an toàn
    auto &blocks = it->second;
    int pos = L;
    for (auto [j,d] : blocks){
        // Gán chữ số cột 'col' cho đoạn [pos..j]
        for (int i = pos; i <= j; ++i) B[i][col] = char('0' + d);
        // Đệ quy sang cột tiếp theo trong đoạn
        buildSolution(col+1, pos, j);
        pos = j + 1;
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    if (!(cin >> n >> m)) return 0;
    A.assign(n, "");
    for (int i = 0; i < n; ++i){
        string s; 
        // đọc đủ m chữ số (bỏ qua khoảng trắng)
        while ((int)A[i].size() < m && (cin >> s)){
            for (char ch : s) if ('0'<=ch && ch<='9') A[i].push_back(ch);
        }
        if ((int)A[i].size() != m){
            cerr << "Input hang " << i+1 << " khong du " << m << " chu so.\n";
            return 0;
        }
    }
 
    // Nếu m cột không đủ để phân biệt n hàng (m quá nhỏ), không khả thi
    auto minCols = [&](int L)->int{
        if (L<=1) return 0;
        int t=0; long long cap=1;
        while (cap < L){ cap *= 10; ++t; }
        return t;
    };
    if (m < minCols(n)){
        // Không thể tăng chặt với cơ số 10 và chỉ m cột
        // (đề thường sẽ không rơi vào TH này)
        cout << "-1\n";
        return 0;
    }
 
    // needCols[L] cho mọi L ≤ n
    needCols[0]=0;
    for (int L=1; L<=n; ++L) needCols[L] = minCols(L);
 
    // Tiền xử lý prefix count cho từng cột
    cnt.resize(m);
    for (int c=0; c<m; ++c){
        for (int d=0; d<10; ++d) cnt[c][d].assign(n+1, 0);
        for (int i=0; i<n; ++i){
            int dig = A[i][c]-'0';
            for (int d=0; d<10; ++d){
                cnt[c][d][i+1] = cnt[c][d][i] + (d==dig);
            }
        }
    }
 
    // Khởi tạo dp = -1
    for (int c=0; c<m; ++c)
        for (int i=0; i<n; ++i)
            for (int j=0; j<n; ++j)
                dp[c][i][j] = -1;
 
    B = A;
    int cost = solve(0, 0, n-1);
    // (cost là số ô phải đổi tối thiểu; không in ra nếu đề không yêu cầu)
    buildSolution(0, 0, n-1);
    cout<<cost<<endl;
    // In dãy bất kỳ đạt tối ưu: n dòng, mỗi dòng m chữ số
    for (int i=0; i<n; ++i) cout << B[i] << '\n';
    return 0;
}