#include <bits/stdc++.h>
using namespace std;
const long long maxn = 1005;
struct node {
  long long v = -1000000007, i, lazy;
  void assign(long long val, long long index) {
    v = val;
    i = index;
    lazy = 0;
  }
  void merge(node &l, node &r) {
    if (l.v >= r.v) {
      v = l.v;
      i = l.i;
    } else {
      v = r.v;
      i = r.i;
    }
    lazy = 0;
  }
} zero;
class segtree {
  node t[4 * maxn];

 public:
  void pushdown(long long v, long long tl, long long tr) {
    if (t[v].lazy) {
      long long ln = v * 2;
      long long rn = v * 2 + 1;
      long long tm = (tl + tr) / 2;
      apply(ln, tl, tm, t[v].lazy);
      apply(rn, tm + 1, tr, t[v].lazy);
      t[v].lazy = 0;
    }
  }
  void apply(long long v, long long tl, long long tr, long long val) {
    if (tl != tr) {
      t[v].lazy += val;
    }
    t[v].v += val;
  }
  void build(long long a[], long long v, long long tl, long long tr) {
    if (tl == tr) {
      t[v].assign(a[tl], tl);
      return;
    } else {
      long long tm = (tl + tr) / 2;
      build(a, v * 2, tl, tm);
      build(a, v * 2 + 1, tm + 1, tr);
      t[v].merge(t[v * 2], t[v * 2 + 1]);
    }
  }
  void build(long long a[]) { build(a, 1, 0, maxn - 1); }
  node query(long long v, long long tl, long long tr, long long l,
             long long r) {
    if (l > tr || r < tl) return zero;
    if (l <= tl && tr <= r) {
      return t[v];
    }
    pushdown(v, tl, tr);
    long long tm = (tl + tr) / 2;
    node a, b, ans;
    a = query(v * 2, tl, tm, l, r);
    b = query(v * 2 + 1, tm + 1, tr, l, r);
    ans.merge(a, b);
    return ans;
  }
  node query(long long l, long long r) { return query(1, 0, maxn - 1, l, r); }
  void rupd(long long v, long long tl, long long tr, long long l, long long r,
            long long val) {
    if (l > tr || r < tl) return;
    if (l <= tl && tr <= r) {
      apply(v, tl, tr, val);
      return;
    }
    pushdown(v, tl, tr);
    long long tm = (tl + tr) / 2;
    rupd(v * 2, tl, tm, l, r, val);
    rupd(v * 2 + 1, tm + 1, tr, l, r, val);
    t[v].merge(t[v * 2], t[v * 2 + 1]);
  }
  void rupd(long long l, long long r, long long val) {
    rupd(1, 0, maxn - 1, l, r, val);
  }
};
long long r[1005], c[1005];
long long a[1000005], b[1000005];
void solve() {
  long long n, m, k, p;
  cin >> n >> m >> k >> p;
  for (long long i = 0; i < n; i++) {
    for (long long j = 0; j < m; j++) {
      long long t;
      cin >> t;
      r[i] += t;
      c[j] += t;
    }
  }
  segtree row;
  segtree column;
  row.build(r);
  column.build(c);
  for (long long z = 1; z < k + 1; z++) {
    node x = row.query(0, n - 1);
    node y = column.query(0, m - 1);
    a[z] = x.v + a[z - 1];
    row.rupd(x.i, x.i, -p * m);
    b[z] = y.v + b[z - 1];
    column.rupd(y.i, y.i, -p * n);
  }
  long long ans = -1000000007 / 1000 * 1LL * 1000000007;
  for (long long i = 0; i < k + 1; i++) {
    long long t = a[i] + b[k - i] - i * (k - i) * p;
    ans = max(t, ans);
  }
  cout << ans;
}
signed main() {
  ios_base::sync_with_stdio(false);
  long long t = 1;
  while (t--) solve();
  return 0;
}
