#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-9;
const double PI = acos((long double)-1.0);
const int INF = 1 << 30;
const long long LINF = 1ll << 61;
const int BUFFER_SZ = 1 << 20;
const int MOD = 1000 * 1000 * 1000 + 9;
char BUFFER[BUFFER_SZ];
int gi() {
  int x;
  scanf("%d", &x);
  return x;
}
double gd() {
  double x;
  scanf("%lf", &x);
  return x;
}
long long gll() {
  long long x;
  cin >> x;
  return x;
}
vector<int> gvi(int n) {
  vector<int> a;
  while (n-- > 0) a.push_back(gi());
  return a;
}
string gs() {
  scanf("%s", BUFFER);
  return string(BUFFER);
}
template <class T>
void print(vector<T> &x, string format) {
  format += "%c";
  for (int i = 0; i < x.size(); ++i)
    printf(format.c_str(), x[i], i + 1 == x.size() ? '\n' : ' ');
}
struct stackMin {
  stack<pair<int, int> > S;
  void push(int x) {
    if (S.empty())
      S.push(make_pair(x, x));
    else
      S.push(make_pair(x, min(S.top().second, x)));
  }
  int pop() {
    int x = S.top().first;
    S.pop();
    return x;
  }
  int getMin() { return S.empty() ? INF : S.top().second; }
  int empty() { return S.empty(); }
};
struct queueMin {
  stackMin S1;
  stackMin S2;
  void push(int x) { S1.push(x); }
  int pop() {
    if (S2.empty()) {
      while (!S1.empty()) {
        S2.push(S1.pop());
      }
    }
    return S2.pop();
  }
  int getMin() { return min(S1.getMin(), S2.getMin()); }
};
int Mline[1024][1024];
long long S[1024][1024];
int A[1024][1024];
int Mn[1024][1024];
int F[1024][1024];
pair<long long, pair<int, int> > C[1 << 20];
int Cn;
inline long long sum(int x1, int y1, int x2, int y2) {
  return S[x2 + 1][y2 + 1] - S[x2 + 1][y1] - S[x1][y2 + 1] + S[x1][y1];
}
void build(int N, int M, int X, int Y) {
  memset((S), (0), sizeof(S));
  for (int i = 1; i <= N; ++i) {
    for (int j = 1; j <= M; ++j) {
      S[i][j] = A[i - 1][j - 1];
      S[i][j] += S[i - 1][j];
      S[i][j] += S[i][j - 1];
      S[i][j] -= S[i - 1][j - 1];
    }
  }
  for (int i = 0; i < N; ++i) {
    queueMin Q;
    for (int j = 0; j < Y - 1; ++j) Q.push(A[i][j]);
    for (int j = Y - 1; j < M; ++j) {
      Q.push(A[i][j]);
      Mline[i][j - Y + 1] = Q.getMin();
      Q.pop();
    }
  }
  for (int j = 0; j < M - Y + 1; ++j) {
    queueMin Q;
    for (int i = 0; i < X - 1; ++i) Q.push(Mline[i][j]);
    for (int i = X - 1; i < N; ++i) {
      Q.push(Mline[i][j]);
      Mn[i - X + 1][j] = Q.getMin();
      Q.pop();
    }
  }
  Cn = 0;
  for (int i = 0; i < N - X + 1; ++i) {
    for (int j = 0; j < M - Y + 1; ++j) {
      C[Cn++] =
          make_pair(sum(i, j, i + X - 1, j + Y - 1) - 1ll * X * Y * Mn[i][j],
                    make_pair(i, j));
    }
  }
}
void solve() {
  int n = gi();
  int m = gi();
  int a = gi();
  int b = gi();
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
      A[i][j] = gi();
    }
  }
  build(n, m, a, b);
  sort(C, C + Cn);
  memset((F), (0), sizeof(F));
  vector<int> res;
  for (int i = 0; i < Cn; ++i) {
    int x = C[i].second.first;
    int y = C[i].second.second;
    if (!F[x][y]) {
      res.push_back(i);
      for (int xx = max(0, x - a + 1); xx <= min(n - 1, x + a - 1); ++xx) {
        for (int yy = max(0, y - b + 1); yy <= min(m - 1, y + b - 1); ++yy) {
          F[xx][yy] = 1;
        }
      }
    }
  }
  printf("%d\n", res.size());
  for (int x : res) {
    printf("%d %d %lld\n", C[x].second.first + 1, C[x].second.second + 1,
           C[x].first);
  }
}
int main() {
  solve();
  return 0;
}
