#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;
}