#include <bits/stdc++.h>
using namespace std;
struct OO {
  OO& operator<(int a) {
    printf("%d", a);
    return *this;
  }
  OO& operator<(long long a) {
    printf("%lld", a);
    return *this;
  }
  OO& operator<(double a) {
    printf("%.15f", a);
    return *this;
  }
  OO& operator<(char a) {
    putchar(a);
    return *this;
  }
  OO& operator<(const char* a) {
    fputs(a, stdout);
    return *this;
  }
} O;
struct II {
  II& operator>(int& a) {
    scanf("%d", &a);
    return *this;
  }
  II& operator>(long long& a) {
    scanf("%lld", &a);
    return *this;
  }
  II& operator>(double& a) {
    scanf("%lf", &a);
    return *this;
  }
  II& operator>(char& a) {
    a = getchar();
    return *this;
  }
} I;
struct EE {
  EE& operator<(int a) { return *this; }
  EE& operator<(long long a) { return *this; }
  EE& operator<(double a) { return *this; }
  EE& operator<(char a) { return *this; }
  EE& operator<(const char* a) { return *this; }
} E;
class UnionFind {
 public:
  UnionFind(size_t univSize) : parents(univSize), ranks(univSize, 0) {
    for (size_t i = 0; i < univSize; ++i) parents[i] = i;
  }
  size_t find(size_t x) {
    size_t root = x;
    while (parents[root] != root) root = parents[root];
    while (x != root) {
      size_t& curr = parents[x];
      x = parents[x];
      curr = root;
    }
    return root;
  }
  bool makeUnion(size_t a, size_t b) {
    a = find(a);
    b = find(b);
    if (a == b) return false;
    if (ranks[a] < ranks[b])
      parents[a] = b, ++ranks[b];
    else
      parents[b] = a, ++ranks[a];
    return true;
  }

 private:
  std::vector<size_t> parents;
  std::vector<size_t> ranks;
};
inline char gc() {
  char c = getchar();
  while (!isgraph(c)) c = getchar();
  return c;
}
int n, m, K, W;
struct plansza {
  unsigned long long data[53][2];
} plansze[1009];
inline void setbit(unsigned long long data[2], int i, int j) {
  int pos = i * 10 + j;
  if (pos < 64)
    data[0] |= (1LL << pos);
  else
    data[1] |= (1LL << (pos - 64));
}
inline int getdiff(int a, int b) {
  int total = 0;
  for (int i = (int)(0); i < (int)(26 * 2 + 1); ++i) {
    long long v = (plansze[a].data[i][0] ^ plansze[b].data[i][0]);
    total += __builtin_popcountll(v);
    v = (plansze[a].data[i][1] ^ plansze[b].data[i][1]);
    total += __builtin_popcountll(v);
  }
  return total >> 1;
}
struct Ed {
  Ed(int a, int b, int c) : fr(a), to(b), w(c) {}
  int fr;
  int to;
  int w;
  bool operator<(const Ed& o) const { return w < o.w; }
};
vector<Ed> edges;
vector<pair<int, int> > dests[1009];
UnionFind uf(1009);
bool vis[1009];
void dfs(int v) {
  if (vis[v]) return;
  vis[v] = true;
  for (int i = (int)(0); i < (int)(dests[v].size()); ++i) {
    int vdest = dests[v][i].first;
    if (!vis[vdest]) {
      if (dests[v][i].second == -1)
        O < vdest + 1 < " " < 0 < '\n';
      else
        O < vdest + 1 < " " < v + 1 < '\n';
      dfs(vdest);
    }
  }
}
int main() {
  I > n > m > K > W;
  int simplecost = n * m;
  for (int k = (int)(0); k < (int)(K); ++k) {
    for (int i = (int)(0); i < (int)(n); ++i)
      for (int j = (int)(0); j < (int)(m); ++j) {
        char c = gc();
        int ic = (c >= 'a' && c <= 'z') ? c - 'a' : 26 + c - 'A';
        if (c == '.') ic = 26 * 2;
        setbit(plansze[k].data[ic], i, j);
      }
  }
  for (int i = (int)(0); i < (int)(K); ++i)
    for (int j = (int)(i + 1); j < (int)(K); ++j) {
      int diff = getdiff(i, j);
      edges.push_back(Ed(i, j, diff));
      E < "dist[" < i < "][" < j < "] == " < diff < '\n';
    }
  sort(edges.begin(), edges.end());
  long long wynik = n * m;
  for (int i = (int)(0); i < (int)((int)edges.size()); ++i) {
    int cost = edges[i].w;
    cost *= W;
    if (cost > simplecost) {
      cost = -1;
    }
    int a = edges[i].fr;
    int b = edges[i].to;
    int aa = uf.find(a);
    int bb = uf.find(b);
    if (aa == bb) continue;
    if (cost == -1)
      wynik += simplecost;
    else
      wynik += cost;
    uf.makeUnion(aa, bb);
    dests[a].push_back(make_pair(b, cost));
    dests[b].push_back(make_pair(a, cost));
  }
  O < wynik < '\n';
  O < 1 < " " < 0 < '\n';
  dfs(0);
  return 0;
}
