#include <bits/stdc++.h>
using namespace std;
int distance(const string& s, const string& t) {
  assert(s.size() == t.size());
  int res = 0;
  for (int i = 0; i < (int)(s.size()); ++i) {
    if (s[i] == t[i]) {
    } else {
      res++;
    }
  }
  return res;
}
int main() {
  int H, W, K, C;
  while (cin >> H >> W >> K >> C) {
    static int d[1000][1000] = {};
    vector<string> str(K);
    for (int i = 0; i < (int)(K); ++i) {
      for (int y = 0; y < (int)(H); ++y) {
        string tmp;
        cin >> tmp;
        str[i] += tmp;
      }
    }
    for (int i = 0; i < K; i++) {
      for (int j = i + 1; j < K; j++) {
        d[i][j] = d[j][i] = distance(str[i], str[j]) * C;
      }
    }
    priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>,
                   greater<tuple<int, int, int>>>
        que;
    vector<int> res(K, H * W);
    for (int i = 0; i < (int)(K); ++i) {
      que.push(tuple<int, int, int>(H * W, -1, i));
    }
    int sum = 0;
    vector<pair<int, int>> use;
    vector<bool> used(K);
    while (!que.empty()) {
      tuple<int, int, int> t = que.top();
      que.pop();
      int c = get<0>(t);
      int from = get<1>(t);
      int v = get<2>(t);
      if (used[v]) continue;
      used[v] = true;
      sum += c;
      use.push_back(make_pair(v + 1, from + 1));
      for (int nv = 0; nv < K; nv++)
        if (nv != v) {
          if (res[nv] > d[v][nv]) {
            res[nv] = d[v][nv];
            que.push(tuple<int, int, int>(res[nv], v, nv));
          }
        }
    }
    cout << sum << endl;
    for (int i = 0; i < (int)(use.size()); ++i) {
      cout << use[i].first << " " << use[i].second << endl;
    }
  }
  return 0;
}
