#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef tree<long long, null_type, less_equal<>,
rb_tree_tag, tree_order_statistics_node_update>
ordered_set;
#define ll long long
#define ii pair<ll,ll>
#define iii tuple<ll,ll,ll>
#ifndef DEBUG
#define cerr if (0) cerr
#define endl '\n'
#endif
const ll inf=1e15;
const ll maxn=2e4+5;
const ll mod=1e9+7;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
ll n, m, k;
vector<ii> v;
short scores[maxn][105];
bool dp[105][10005][105]; //index, excluded sum, number excluded
vector<tuple<short, short, int>> segments[maxn];
void reset(ll size) {
for (int i = 1; i < 105; i++) {
for (int j = 1; j <= size; j++) {
for (int l = 1; l < 105; l++) {
dp[i][j][l] = 0;
}
}
}
}
void solve(ll size, ll idx, ll pos) {
ll tot = v[pos].first;
dp[0][0][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= size; j++) {
for (int l = 0; l <= m; l++) {
bool can1 = false, can2 = false;
if (j - scores[idx][i] >= 0 && l - 1 >= 0){
can1 = dp[i - 1][j - scores[idx][i]][l - 1];
}
can2 = dp[i - 1][j][l];
dp[i][j][l] = can1 | can2;
if (dp[i][j][l]) {
segments[idx].emplace_back(tot - j + l * k,
tot - j, l);
}
}
}
}
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
ll tot = 0;
for (int j = 1; j <= m; j++) {
cin >> scores[i][j];
tot += scores[i][j];
}
v.emplace_back(tot, -i);
}
v.emplace_back(0, -inf);
v.emplace_back(inf, -inf);
sort(v.rbegin(), v.rend());
for (int i = 0; i < v.size(); i++) {
v[i].second = -v[i].second;
}
for (int i = 1; i <= n; i++) {
ll diff = v[i].first - v[i + 1].first;
ll idx = v[i].second;
solve(diff, idx, i);
reset(diff);
}
set<pair<short, int>> curr, prev;
prev.emplace(m * k, 0);
ll prevIdx = -1;
for (auto [tot, idx]: v) {
if (idx == inf) continue;
sort(segments[idx].rbegin(), segments[idx].rend());
bool tieBreak = idx < prevIdx;
prevIdx = idx;
for (auto [r, l, v]: segments[idx]) {
auto it = prev.lower_bound(make_pair(r + tieBreak, -1));
if (it == prev.end()) continue;
curr.emplace(l, it-> second + v);
}
auto it = --curr.end();
--it;
while (curr.size() > 1) {
auto nxt = it;
++nxt;
bool isErase = (it -> second <= nxt -> second);
auto toErase = it;
bool isBegin = (it == curr.begin());
--it;
if (isErase) {
curr.erase(toErase);
}
if (isBegin) break;
}
swap(curr, prev);
curr.clear();
}
cout << m * n - prev.begin() -> second;
return 0;
}