Problem:
Planning Rolling Blackouts
Faced with seriously tight power supply-demand balance, the
electric power company for which you are working implemented
rolling
    blackouts
in this spring.  It divided the servicing area into several
groups of towns, and divided a day into several blackout periods.  At
each blackout period of a day, one of the groups, which alternates
from one group to another, is cut off the electricity.  By keeping the total demand of
electricity used by the rest of the towns within the supply
capacity, the company avoided unforeseeable large-scale blackout.
Working at the customer relations department, you had to listen to
so many complaints from the customers, which made you think that you
could have a better implementation.  Most of the complaints are about the
frequent cut-offs.  But you could have divided the area into a larger number of
groups, which resulted in less frequent cut-offs for each group.  The
other complaints are about the complicated grouping (in fact, someone
said that the shapes of the groups are fractals), which makes it
impossible to understand which town belongs to which group without
closely inspecting into the grouping list publicized by the company.
With the rectangular servicing area and towns located in a grid form,
you could have made a simpler grouping.
When you talked your analysis directly to the president of the company, you are
appointed to plan rolling blackouts for this summer.  Be careful what
you propose.  Anyway, you need to divide the servicing area into
as many groups as possible with keeping total demand of electricity
within the supply capacity.  It should also divide the towns into
simple and easy to remember groups.
Your task is to write a program, given a demand table (a table showing
electricity demand of each town) and the supply capacity, that answers
a grouping of towns that satisfy the following conditions.
The grouping should be made by horizontally or vertically splitting
    the area in a recursive manner.  In other words, the grouping must
    be a set of areas after applied the following splitting
    procedure to a set containing only the entire area for zero or
    more times:
(The splitting procedure) remove one area from the set,
      either vertically or horizontally split it into two sub-areas,
      and put the sub-areas into the set.
The maximum suppressed demand of the grouping, which is the greatest total demand of the
    all but one group, is no more than the supply capacity.
The grouping has the largest number of groups among the groupings
    that satisfy the above conditions 1 and 2.
The grouping has the greatest amount of reserve power among the
  groupings that satisfy the above conditions 1, 2 and 3, where the
  reserve power of a grouping is the difference between the supply
  capacity and the maximum suppressed demand.
Note that the condition 1 does not allow such a grouping shown in Figure E-1.
Figure E-1: A grouping that violates the condition 1
Input

...(truncated)

Submitted solutions:

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
const int oo=1073741819;
using namespace std;
int n,m,s,w_time;
int sum[50][50],t[50][50][50][50],a[50][50];
struct sta{
    int tot,max;
}f[50][50][50][50];
void updata(sta &x,sta a,sta b)
{
    if (!a.tot || !b.tot) return ;
    if (a.tot+b.tot>x.tot) {
        x.tot=a.tot+b.tot;
        x.max=min(a.max,b.max);
//        if (x.tot==5) cout<<a.tot<<' '<<b.tot<<endl;
    }
    else if (a.tot+b.tot==x.tot) {
        if (min(a.max,b.max)>x.max) 
            x.max=min(a.max,b.max);
    }
}
void print(sta a)
{
    cout<<a.tot<<' '<<a.max<<endl;
}
void dfs(int lx,int ly,int rx,int ry)
{
    if (t[lx][ly][rx][ry]==w_time) return ;
//    cout<<lx<<' '<<ly<<' '<<rx<<' '<<ry<<endl;
    t[lx][ly][rx][ry]=w_time;
    f[lx][ly][rx][ry].tot=0,
        f[lx][ly][rx][ry].max=-oo;
    if (lx==rx && ly==ry) {
        if (sum[n][m]-a[lx][ly]<=s) {
            f[lx][ly][rx][ry].tot=1;
            f[lx][ly][rx][ry].max=s-(sum[n][m]-a[lx][ly]);
        }
        return ;
    }
    int Sum=sum[rx][ry]-sum[rx][ly-1]-sum[lx-1][ry]+sum[lx-1][ly-1];
    if (sum[n][m]-Sum<=s) {
        f[lx][ly][rx][ry].tot=1;
        f[lx][ly][rx][ry].max=s-(sum[n][m]-Sum);
    }
    for (int i=lx;i<=rx-1;i++) {
        dfs(lx,ly,i,ry);
        dfs(i+1,ly,rx,ry);
        updata(f[lx][ly][rx][ry],f[lx][ly][i][ry],f[i+1][ly][rx][ry]);
    //    print(f[lx][ly][rx][ry]);
    }
    for (int i=ly;i<=ry-1;i++) {
        dfs(lx,ly,rx,i);
        dfs(lx,i+1,rx,ry);
        updata(f[lx][ly][rx][ry],f[lx][ly][rx][i],f[lx][i+1][rx][ry]);
    //    print(f[lx][ly][rx][ry]);
    }
//   cout<<lx<<' '<<ly<<' '<<rx<<' '<<ry<<endl;
//    print(f[lx][ly][rx][ry]);
}
int main()
{
    for (;scanf("%d%d%d",&n,&m,&s)==3;) {
        if (!n && !m && !s) break;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                scanf("%d",&a[i][j]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) 
                sum[i][j]=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j];
        w_time++;
 //       cout<<n<<' '<<m<<endl;
        dfs(1,1,n,m);
        printf("%d %d\n",f[1][1][n][m].tot,f[1][1][n][m].max);
    }
    return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 53172
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

constexpr pair<int, int> INIT = {-1, -1};

void solve(int h, int w, int s, vector<vector<int>> u) {
    vector<vector<int>> pref(h + 1, vector<int>(w + 1, 0));
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            pref[i + 1][j + 1] = pref[i][j + 1] + pref[i + 1][j] - pref[i][j] + u[i][j];
        }
    }
    auto get_pref = [&](int x1, int y1, int x2, int y2) { return pref[x2][y2] - pref[x1 - 1][y2] - pref[x2][y1 - 1] + pref[x1 - 1][y1 - 1]; };
    int total     = get_pref(1, 1, h, w);

    auto chmax = [](pair<int, int>& a, pair<int, int>& b) -> bool {
        if (a.first == b.first && a.second < b.second) {
            a = b;
            return true;
        }
        if (a.first < b.first) {
            a = b;
            return true;
        }
        return false;
    };

    // dp[x1][y1][x2][y2] := x1,y1が左上,x2,y2が右下の長方形内の{グループの最大個数, 予備電力}
    vector dp(h + 1, vector(w + 1, vector(h + 1, vector<pair<int, int>>(w + 1, {-1, -1}))));
    auto dfs = [&](auto dfs, int x1, int y1, int x2, int y2) -> pair<int, int> {
        if (dp[x1][y1][x2][y2] != INIT) {
            return dp[x1][y1][x2][y2];
        }

        if (total - get_pref(x1, y1, x2, y2) > s) {
            return dp[x1][y1][x2][y2] = INIT;
        }

        pair<int, int> ret = {1, s - (total - get_pref(x1, y1, x2, y2))};
        for (int nx = x1; nx < x2; nx++) {
            auto g1 = dfs(dfs, x1, y1, nx, y2);
            auto g2 = dfs(dfs, nx + 1, y1, x2, y2);
            if (g1 == INIT || g2 == INIT) {
                continue;
            }
            pair<int, int> res = {g1.first + g2.first, min(g1.second, g2.second)};
            chmax(ret, res);
        }
        for (int ny = y1; ny < y2; ny++) {
            auto g1 = dfs(dfs, x1, y1, x2, ny);
            auto g2 = dfs(dfs, x1, ny + 1, x2, y2);
            if (g1 == INIT | g2 == INIT) {
                continue;
            }
            pair<int, int> res = {g1.first + g2.first, min(g1.second, g2.second)};
            chmax(ret, res);
        }

        return dp[x1][y1][x2][y2] = ret;
    };

    auto ans = dfs(dfs, 1, 1, h, w);
    cout << ans.first << " " << ans.second << endl;
}

int main() {
    while (true) {
        int h, w, s;
        cin >> h >> w >> s;
        if (h == 0 && w == 0 && s == 0) {
            break;
        }
        vector<vector<int>> u(h, vector<int>(w));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                cin >> u[i][j];
            }
        }
        solve(h, w, s, u);
    }
}
accuracy: 1
time_ms: 290
memory_kb: 14212
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

constexpr pair<int, int> INIT = {-1, -1};

void solve(int h, int w, int s, vector<vector<int>> u) {
    vector<vector<int>> pref(h + 1, vector<int>(w + 1, 0));
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            pref[i + 1][j + 1] = pref[i][j + 1] + pref[i + 1][j] - pref[i][j] + u[i][j];
        }
    }
    auto get_pref = [&](int x1, int y1, int x2, int y2) { return pref[x2][y2] - pref[x1 - 1][y2] - pref[x2][y1 - 1] + pref[x1 - 1][y1 - 1]; };
    int total = get_pref(1, 1, h, w);
    
    auto chmax = [&](pair<int, int>& a, pair<int, int>& b) -> bool {
        if (a.first == b.first && a.second < b.second) {
            a = b;
            return true;
        }
        if (a.first < b.first) {
            a = b;
            return true;
        }
        return false;
    };

    // dp[x1][y1][x2][y2] := x1,y1が左上,x2,y2が右下の長方形内の{グループの最大個数, 予備電力}
    vector dp(h + 1, vector(w + 1, vector(h + 1, vector<pair<int, int>>(w + 1, {-1, -1}))));
    auto dfs = [&](auto dfs, int x1, int y1, int x2, int y2) -> pair<int, int> {
        if (dp[x1][y1][x2][y2] != INIT) {
            return dp[x1][y1][x2][y2];
        }

        if (total - get_pref(x1, y1, x2, y2) > s) {
            return dp[x1][y1][x2][y2] = INIT;
        }

        pair<int, int> ret = {1, s - (total - get_pref(x1, y1, x2, y2))};
        for (int nx = x1; nx < x2; nx++) {
            auto g1 = dfs(dfs, x1, y1, nx, y2);
            auto g2 = dfs(dfs, nx + 1, y1, x2, y2);
            if (g1 == INIT || g2 == INIT) {
                continue;
            }
            auto [f1, s1]      = g1;
            auto [f2, s2]      = g2;
            pair<int, int> res = {f1 + f2, min(s1, s2)};
            chmax(ret, res);
        }
        for (int ny = y1; ny < y2; ny++) {
            auto g1 = dfs(dfs, x1, y1, x2, ny);
            auto g2 = dfs(dfs, x1, ny + 1, x2, y2);
            if (g1 == INIT || g2 == INIT) {
                continue;
            }
            auto [f1, s1]      = g1;
            auto [f2, s2]      = g2;
            pair<int, int> res = {f1 + f2, min(s1, s2)};
            chmax(ret, res);
        }

        return dp[x1][y1][x2][y2] = ret;
    };

    auto ans = dfs(dfs, 1, 1, h, w);
    cout << ans.first << " " << ans.second << endl;
}

int main() {
    while (true) {
        int h, w, s;
        cin >> h >> w >> s;
        if (h == 0 && w == 0 && s == 0) {
            break;
        }
        vector<vector<int>> u(h, vector<int>(w));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                cin >> u[i][j];
            }
        }
        solve(h, w, s, u);
    }
}
accuracy: 1
time_ms: 290
memory_kb: 14280
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

constexpr pair<int, int> INIT = {-1, -1};

void solve(int h, int w, int s, vector<vector<int>> u) {
    vector<vector<int>> pref(h + 1, vector<int>(w + 1, 0));
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            pref[i + 1][j + 1] = pref[i][j + 1] + pref[i + 1][j] - pref[i][j] + u[i][j];
        }
    }
    auto get_pref = [&](int x1, int y1, int x2, int y2) { return pref[x2][y2] - pref[x1 - 1][y2] - pref[x2][y1 - 1] + pref[x1 - 1][y1 - 1]; };

    int total = get_pref(1, 1, h, w);

    auto chmax = [&](pair<int, int>& a, pair<int, int>& b) -> bool {
        if (a.first == b.first && a.second < b.second) {
            a = b;
            return true;
        }
        if (a.first < b.first) {
            a = b;
            return true;
        }
        return false;
    };

    // dp[x1][y1][x2][y2] := x1,y1が左上,x2,y2が右下の長方形内の{グループの最大個数, 予備電力}
    vector dp(h + 1, vector(w + 1, vector(h + 1, vector<pair<int, int>>(w + 1, {-1, -1}))));
    auto dfs = [&](auto dfs, int x1, int y1, int x2, int y2) -> pair<int, int> {
        if (dp[x1][y1][x2][y2] != INIT) {
            return dp[x1][y1][x2][y2];
        }

        if (total - get_pref(x1, y1, x2, y2) > s) {
            return dp[x1][y1][x2][y2] = INIT;
        }

        pair<int, int> ret = {1, s - (total - get_pref(x1, y1, x2, y2))};
        for (int nx = x1; nx < x2; nx++) {
            auto g1 = dfs(dfs, x1, y1, nx, y2);
            auto g2 = dfs(dfs, nx + 1, y1, x2, y2);
            if (g1 == INIT || g2 == INIT) {
                continue;
            }
            auto [f1, s1]      = g1;
            auto [f2, s2]      = g2;
            pair<int, int> res = {f1 + f2, min(s1, s2)};
            chmax(ret, res);
        }
        for (int ny = y1; ny < y2; ny++) {
            auto g1 = dfs(dfs, x1, y1, x2, ny);
            auto g2 = dfs(dfs, x1, ny + 1, x2, y2);
            if (g1 == INIT || g2 == INIT) {
                continue;
            }
            auto [f1, s1]      = g1;
            auto [f2, s2]      = g2;
            pair<int, int> res = {f1 + f2, min(s1, s2)};
            chmax(ret, res);
        }

        return dp[x1][y1][x2][y2] = ret;
    };

    auto ans = dfs(dfs, 1, 1, h, w);
    cout << ans.first << " " << ans.second << endl;
}

int main() {
    while (true) {
        int h, w, s;
        cin >> h >> w >> s;
        if (h == 0 && w == 0 && s == 0) {
            break;
        }
        vector<vector<int>> u(h, vector<int>(w));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                cin >> u[i][j];
            }
        }
        solve(h, w, s, u);
    }
}
accuracy: 1
time_ms: 290
memory_kb: 14212
final_rank: 9

code_snippet: //#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,n) for (ll i=0;i<(ll)n;i++)
#define rrep(i,n) for (ll i=n-1;i>=(ll)0;i--)
#define loop(i,m,n) for(ll i=m;i<=(ll)n;i++)
#define rloop(i,m,n) for(ll i=m;i>=(ll)n;i--)
#define vl vector<ll>
#define vvl vector<vector<ll>>
#define vdbg(a) rep(ii,a.size()){cout<<a[ii]<<" ";}cout<<endl;
#define vpdbg(a) rep(ii,a.size()){cout<<"{"<<a[ii].first<<","<<a[ii].second<<"} ";}cout<<endl;
#define vvdbg(a) rep(ii,a.size()){rep(jj,a[ii].size()){cout<<a[ii][jj]<<" ";}cout<<endl;}
#define setdbg(a) for(const auto & ii:a){cout<<ii<<" ";}cout<<endl;
#define inf 1e9
#define mod 998244353LL
//#define mod 1000000007LL
#define eps 0.000000001
random_device rnd;// 非決定的な乱数生成器
mt19937 mt(rnd());// メルセンヌ・ツイスタの32ビット版、引数は初期シード

//#include<boost/multiprecision/cpp_int.hpp>
//#define bbi boost::multiprecision::cpp_int
//#include<atcoder/lazysegtree>


//整数同士の累乗の計算をする。
ll power(ll A, ll B) {
	ll result = 1;
	for (ll i=0;i<B;i++){
		result *= A;
	}
	return result;
}

// nのk乗をmodで割った余りを計算
ll power_mod(ll n, ll k){
	long long result = 1;
	while (k > 0){
		if ((k&1) ==1)result=(result*n)%mod;
		n=n*n%mod;
		k >>= 1;
	}
	return result;
}


//受け取った2次元文字の外側に、文字pをコーティングする。
vector<string> pad(vector<string> &s,char p){
	ll h=s.size();
	ll w=s[0].size();
	vector<string> res(h+2,string(w+2,p));
	rep(i,h)rep(j,w)res[i+1][j+1]=s[i][j];
	return res;
}

// Union-Find
struct UnionFind {
	vector<int> par, siz;
	UnionFind(int n) : par(n, -1) , siz(n, 1) { }
	// 根を求める
	int root(int x) {
		if (par[x] == -1) return x;
		else return par[x] = root(par[x]);
	}
	// x と y が同じグループに属するかどうか (根が一致するかどうか)
	bool issame(int x, int y) {
		return root(x) == root(y);
	}
	// x を含むグループと y を含むグループとを併合する
	bool unite(int x, int y) {
		x = root(x), y = root(y);
		if (x == y) return false; 
		if (siz[x] < siz[y]) swap(x, y);
		par[y] = x;
		siz[x] += siz[y];
		return true;
	}
	// x を含むグループのサイズ
	int size(int x) {
		return siz[root(x)];
	}
};


//グリッド問題等用
vl dx={1,0,-1,0};
vl dy={0,1,0,-1};

ll s;
vvl u;
unordered_map<ll,pair<ll,ll>> dp;
vvl sums;

pair<ll,ll> dfs(ll aa){
	if(dp.count(aa))return dp[aa];
	vl a;
	a.push_back(aa%32);
	a.push_back((aa/32)%32);
	a.push_back((aa/1024)%32);
	a.push_back((aa/32768)%32);

	ll sum=sums[a[0]][a[1]]+sums[a[2]+1][a[3]+1]-sums[a[0]][a[3]+1]-sums[a[2]+1][a[1]];

	if(sum<s){
		pair<ll,ll> ans={-inf,0};
		dp[aa]=ans;
		return ans;
	}
	pair<ll,ll> ans={1,sum-s};
	if(sum<s*2){
		dp[aa]=ans;
		return ans;
	}
	
	//iの下に横線で切る
	loop(i,a[0],a[2]-1){
		ll first=a[0]+a[1]*32+i*1024+a[3]*32768;
		ll second=i+1+a[1]*32+a[2]*1024+a[3]*32768;
		pair<ll,ll> tmp=dfs(first);
		pair<ll,ll> tmp2=dfs(second);
		ans=max(ans,{tmp.first+tmp2.first,min(tmp.second,tmp2.second)});
	}

	//iの右に縦線で切る
	loop(i,a[1],a[3]-1){
		ll first=a[0]+a[1]*32+a[2]*1024+i*32768;
		ll second=a[0]+(i+1)*32+a[2]*1024+a[3]*32768;
		pair<ll,ll> tmp=dfs(first);
		pair<ll,ll> tmp2=dfs(second);
		ans=max(ans,{tmp.first+tmp2.first,min(tmp.second,tmp2.second)});
	}

	dp[aa]=ans;
	return ans;
}

ll solve(){
	ll h,w;
	cin>>h>>w>>s;
	if(h==0){return 1;}
	u=vvl(h,vl(w));
	sums=vvl(h+1,vl(w+1,0));
	dp.clear();

	rep(i,h)rep(j,w){
		cin>>u[i][j];
		sums[i+1][j+1]=sums[i+1][j]+sums[i][j+1]-sums[i][j]+u[i][j];
	}
	
	s=sums[h][w]-s;

	ll tmp=(h-1)*1024+(w-1)*32768;
	pair<ll,ll> ans=dfs(tmp);
	cout<<ans.first<<" "<<ans.second<<"\n";
	
	return 0;
}

//メイン
int main(){
	while(solve()==0);
	return 0;
}
accuracy: 1
time_ms: 1330
memory_kb: 19684
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef int ll;
typedef unsigned long long ull;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define rrep(i,start,end) for (ll i = start;i >= (ll)(end);i--)
#define repn(i,end) for(ll i = 0; i <= (ll)(end); i++)
#define reps(i,start,end) for(ll i = start; i < (ll)(end); i++)
#define repsn(i,start,end) for(ll i = start; i <= (ll)(end); i++)
#define each(p,a) for(auto &p:a)
typedef vector<ll> vll;
typedef vector<pair<ll ,ll>> vpll;
typedef vector<vector<ll>> vvll;
typedef set<ll> sll;
typedef map<ll , ll> mpll;
typedef pair<ll ,ll> pll;
typedef tuple<ll , ll , ll> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (ll)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1 << 30;
const ld EPS = 1e-9;
 
ll lceil(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b)+1;}else{return -((-a)/b);}}
ll lfloor(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b);}else{return -((-a)/b)-1;}}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
//0indexed
inline ll topbit(ll a){assert(a != 0);return 63 - __builtin_clzll(a);}
inline ll smlbit(ll a){assert(a != 0);return __builtin_ctzll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;

// for AOJ or ICPC or etc..
template<class Tp>
bool zero (const Tp &x) {
    return x == 0;
}

template<class Tp, class... Args>
bool zero (const Tp &x, const Args& ...args) {
    return zero(x) and zero(args...);
}

void solve(ll h,ll w,ll s){
  vvll u(h,vll(w));
  ll usum = 0;
  rep(i,h){
    cin >> u[i];
    rep(j,w){
      usum += u[i][j];
    }
  }
  vvll sum(h+1,vll(w+1));
  rep(i,h){
    rep(j,w){
      sum[i+1][j+1] = sum[i+1][j] + sum[i][j+1] - sum[i][j] + u[i][j]; 
    }
  }
  auto getsum = [&](ll yl,ll yr,ll xl,ll xr){
    return sum[yr][xr] - sum[yr][xl] - sum[yl][xr] + sum[yl][xl];
  };
  ll least = usum - s;
  vector dp(h+1,vector(h+1,vector(w+1,vector<ll>(w+1,INF))));//個数、予備(leastと最小の差の最大)
  ll key  = 10000;
  auto cmax = [&](ll &x,ll y) {
    ll xnum = x % key;
    ll xyobi= x / key;
    
    ll ynum = y % key;
    ll yyobi= y / key;
    if(xnum <ynum){
      x = y;
    }else if(xnum == ynum && xyobi < yyobi){
      x = y;
    }
  };
  auto clc = [&](ll num,ll yobi){
    return num + key * yobi;
  };
  auto revclc = [&](ll x) -> pll {
    ll num = x % key;
    ll yobi = x/ key;
    return {num,yobi};
  };
  ll badnum = 5000;
  auto dfs = [&](auto dfs, ll yl,ll yr,ll xl,ll xr)->ll {
    if(dp[yl][yr][xl][xr] != INF){
      return dp[yl][yr][xl][xr];
    }
    if(getsum(yl,yr,xl,xr) < least){//それがだめ
      return dp[yl][yr][xl][xr] = badnum;
    }
    //縦
    ll ans = clc(1,getsum(yl,yr,xl,xr)-least);
    reps(i,yl+1,yr){
      auto [num1,yobi1] = revclc(dfs(dfs,yl,i,xl,xr));
      auto [num2,yobi2] = revclc(dfs(dfs,i,yr,xl,xr));
      if(num1 == badnum or num2 == badnum)continue;
      cmax(ans,clc(num1+num2,min(yobi1,yobi2)));
    }
    reps(j,xl+1,xr){
      auto [num1,yobi1] = revclc(dfs(dfs,yl,yr,xl,j));
      auto [num2,yobi2] = revclc(dfs(dfs,yl,yr,j,xr));
      if(num1 == badnum or num2 == badnum)continue;
      cmax(ans,clc(num1+num2,min(yobi1,yobi2)));
    }
    return dp[yl][yr][xl][xr] = ans;
  };
  auto [num,yobi] = revclc(dfs(dfs,0,h,0,w));

  cout << num << " " << yobi << endl;

}

 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  while(true){
    LL(h,w,s);;
    if(zero(h,w,s))break;
    solve(h,w,s);
  }
}
accuracy: 1
time_ms: 350
memory_kb: 9620
final_rank: 1

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

#ifndef ONLINE_JUDGE
#define _GLIBCXX_DEBUG // 配列外参照のエラー
#endif

// スタンダードライブラリ
#include <bits/stdc++.h>
using namespace std;

// 多倍長整数
//  #if __has_include(<boost/multiprecision/cpp_int.hpp>)
//  #include <boost/multiprecision/cpp_int.hpp>
//  using lll =boost::multiprecision::int128_t;
//  #endif

// atcoder関連
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
using mint = modint998244353;
using MINT = modint1000000007;
#endif

// 型関連
using ll = long long;
using lint = long long;
using pll = pair<ll, ll>;
using plll = tuple<ll, ll, ll>;
using pii = pair<int, int>;
using piii = tuple<ll, ll, ll>;
template <class T> using prique = priority_queue<T>;

// 型定数
constexpr ll mod = 998244353;
constexpr ll MOD = 1000000007;
int inf = 2e9;
ll INF = 9e18;
#define endl '\n';

// 新規マクロ
#define all(a) (a).begin(), (a).end()
#define rep(i, N, limit) for (int i = (int)N; i < (int)limit; i++)

///////////////////// vector関連
template <class T, size_t n, size_t idx = 0>
auto make_vec(const size_t (&d)[n], const T &init) noexcept {
    if constexpr (idx < n)
        return std::vector(d[idx], make_vec<T, n, idx + 1>(d, init));
    else
        return init;
}

template <class T, size_t n> auto make_vec(const size_t (&d)[n]) noexcept {
    return make_vec(d, T{});
}

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

/////////////////////////// print関連
template <typename T> void print(vector<T> A);
void print();
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail);
void print(string S);
template <typename T> void print(vector<vector<T>> &F);

////////////////////////////
inline string input();
inline ll I();
inline pll II();

/////////////////////出力関連
inline void Yes(bool f);

///////////////////ここから//////////////////////

bool solve() {
    int H, W, S;
    cin >> H >> W >> S;
    if (H == 0) {
        return false;
    }
    int all_sum = 0;
    vector<vector<int>> F(H, vector<int>(W));
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> F[i][j];
            all_sum += F[i][j];
        }
    }
    vector<vector<int>> psum(H + 1, vector<int>(W + 1));
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            psum[i + 1][j + 1] = F[i][j];
        }
    }
    for (int i = 0; i < H + 1; i++) {
        for (int j = 0; j < W; j++) {
            psum[i][j + 1] += psum[i][j];
        }
    }
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W + 1; j++) {
            psum[i + 1][j] += psum[i][j];
        }
    }

    auto kukei = [&](int x_l, int x_r, int y_l, int y_r) {
        return psum[x_r][y_r] - psum[x_r][y_l] - psum[x_l][y_r] +
               psum[x_l][y_l];
    };

    vector<vector<vector<vector<int>>>> memo;
    memo.assign(H + 1,
                vector<vector<vector<int>>>(
                    H + 1, vector<vector<int>>(W + 1, vector<int>(W + 1, -1))));

    auto reset = [&]() {
       memo.assign(H + 1,
                vector<vector<vector<int>>>(
                    H + 1, vector<vector<int>>(W + 1, vector<int>(W + 1, -1))));
    };
    auto f = [&](auto &f, int g_min, int x_l, int x_r, int y_l,
                 int y_r) -> int {
        if (memo[x_l][x_r][y_l][y_r] != -1) {
            return memo[x_l][x_r][y_l][y_r];
        }
        if (kukei(x_l, x_r, y_l, y_r) < g_min) {
            return -1000000;
        }
        int ret = 1;
        for (int i = x_l + 1; i < x_r; i++) {
            if (kukei(x_l, i, y_l, y_r) >= g_min &&
                kukei(i, x_r, y_l, y_r) >= g_min) {
                ret = max(ret, f(f, g_min, x_l, i, y_l, y_r) +
                                   f(f, g_min, i, x_r, y_l, y_r));
            }
        }
        for (int i = y_l + 1; i < y_r; i++) {
            if (kukei(x_l, x_r, y_l, i) >= g_min &&
                kukei(x_l, x_r, i, y_r) >= g_min) {
                ret = max(ret, f(f, g_min, x_l, x_r, y_l, i) +
                                   f(f, g_min, x_l, x_r, i, y_r));
            }
        }
        memo[x_l][x_r][y_l][y_r] = ret;
        return ret;
    };

    reset();
    int g_count = f(f, all_sum - S, 0, H, 0, W);
    int ok = all_sum - S, ng = 200000;
    while (ng - ok > 1) {
        int mid = (ng + ok) / 2;
        reset();
        if (f(f, mid, 0, H, 0, W) >= g_count) {
            ok = mid;
        } else {
            ng = mid;
        }
    }

    print(g_count, S - (all_sum - ok));

    return true;
}
int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    while (solve())
        ;
}

////////////////////print/////////////////////////
// 1次元ベクトルを出力する
template <typename T> void print(vector<T> A) {
    if (A.size() == 0) {
        return;
    }
    for (size_t i = 0; i < A.size() - 1; i++) {
        cout << A[i] << ' ';
    }
    cout << A[A.size() - 1] << endl;
    return;
}

// 2次元ベクトルを出力する
template <typename T> void print(vector<vector<T>> &F) {
    for (size_t i = 0; i < F.size(); i++) {
        for (size_t j = 0; j < F[i].size(); j++) {
            cout << F[i][j];
            if (j < F[i].size() - 1) {
                cout << ' ';
            }
        }
        cout << endl;
    }
}

// 空白行を出力するprint
void print() { cout << endl; }

// 数値・文字列を空白区切りで出力する. print(a,b)など
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    cout << head;
    if (sizeof...(tail) != 0)
        cout << " ";
    print(forward<Tail>(tail)...);
}

void print(string S) { cout << S << endl; }

/////////////////////初期化///////////////////////

inline string input() {
    string S;
    cin >> S;
    return S;
}
inline ll I() {
    ll ret;
    cin >> ret;
    return ret;
}
inline pll II() {
    pll ret;
    cin >> ret.first >> ret.second;
    return ret;
}

//////////////出力関連

inline void Yes(bool f) {
    if (f) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
}
accuracy: 1
time_ms: 6710
memory_kb: 10900
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<int,int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;
#define rep(i, n) for(int i = 0; i < (int)(n); i++)
#define FOR(i, a, b) for(ll i = a; i < (ll)(b); i++)
#define all(a) (a).begin(),(a).end()
constexpr int INF = 1001001001;
constexpr ll LINF = 1001001001001001001ll;
constexpr int DX[] = {1, 0, -1, 0};
constexpr int DY[] = {0, 1, 0, -1};

bool solve(){
    int h, w, s;
    cin >> h >> w >> s;
    if(h == 0) return false;
    vvi u(h+1, vi(w+1, 0));
    rep(i, h) rep(j, w) cin >> u[i+1][j+1];
    int sum = 0;
    rep(i, h) rep(j, w) sum += u[i+1][j+1];
    rep(i, h+1) rep(j, w) u[i][j+1] += u[i][j];
    rep(j, w+1) rep(i, h) u[i+1][j] += u[i][j]; 
    int lb = sum - s;
    map<pair<P, P>, P> mp;
    auto f = [&](auto self, int si, int sj, int ti, int tj) -> P{
        if(mp.count({{si, sj}, {ti, tj}})) return mp[{{si, sj}, {ti, tj}}];
        int subsum = u[ti][tj] + u[si][sj] - u[ti][sj] - u[si][tj];
        if(subsum < lb) return {0, 0};
        P ret = {1, s - (sum - subsum)};
        for(int mi = si+1; mi < ti; mi++){
            P l = self(self, si, sj, mi, tj);
            P r = self(self, mi, sj, ti, tj);
            if(l.first == 0) continue;
            if(r.first == 0) continue;
            if(ret.first < l.first+r.first){
                ret = {l.first+r.first, min(l.second, r.second)};
            }
            else if(ret.first == l.first+r.first && ret.second < min(l.second, r.second)){
                ret = {l.first+r.first, min(l.second, r.second)};
            }
        }
        for(int mj = sj+1; mj < tj; mj++){
            P l = self(self, si, sj, ti, mj);
            P r = self(self, si, mj, ti, tj);
            if(l.first == 0) continue;
            if(r.first == 0) continue;
            if(ret.first < l.first+r.first){
                ret = {l.first+r.first, min(l.second, r.second)};
            }
            else if(ret.first == l.first+r.first && ret.second < min(l.second, r.second)){
                ret = {l.first+r.first, min(l.second, r.second)};
            }
        }
        return mp[{{si, sj}, {ti, tj}}] = ret;
    };
    auto ans = f(f, 0, 0, h, w);
    cout << ans.first << " " << ans.second << endl;
    return true;
}

int main(){
    while(solve());
}
accuracy: 1
time_ms: 7080
memory_kb: 20756
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll=long long;
using ull=unsigned long long;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
#define loop(n) for (int tjh = 0; tjh < (int)(n); tjh++)
#define j0 jtmp0
#define j1 jtmp1
constexpr int maxh=32;constexpr int mi=-1000'000;
int h,w,s;
array<array<int,maxh+1>,maxh+1>u;
array<array<array<array<array<int,2>,maxh>,maxh>,maxh>,maxh>v;
int p;array<int,2>t;
signed main() {
  cin.tie(0)->sync_with_stdio(0);
  cout<<fixed<<setprecision(16);
  for(;cin>>h>>w>>s,h;){
    rep(i,h)rep(j,w)cin>>u[i+1][j+1];
    rep(i,h+1)rep(j,w)u[i][j+1]+=u[i][j];
    rep(i,h)rep(j,w+1)u[i+1][j]+=u[i][j];
    s=u[h][w]-s;
    rep(k,h)rep(l,w)rep(i0,h-k)rep(j0,w-l){
      int i1=i0+k;int j1=j0+l;int i2=i1+1;int j2=j1+1;
      p=u[i2][j2]-u[i0][j2]-u[i2][j0]+u[i0][j0]-s;
      if(p<0){
	v[i0][i1][j0][j1]={mi,mi};
	continue;
      }
      v[i0][i1][j0][j1]={1,p};
      rep(i,i1-i0){
	t={
	  v[i0][i0+i][j0][j1][0]+v[i0+i+1][i1][j0][j1][0],
	  min(v[i0][i0+i][j0][j1][1],v[i0+i+1][i1][j0][j1][1])
	};
	if(v[i0][i1][j0][j1]<t)v[i0][i1][j0][j1]=t;
      }
      rep(i,j1-j0){
	t={
	  v[i0][i1][j0][j0+i][0]+v[i0][i1][j0+i+1][j1][0],
	  min(v[i0][i1][j0][j0+i][1],v[i0][i1][j0+i+1][j1][1])
	};
	if(v[i0][i1][j0][j1]<t)v[i0][i1][j0][j1]=t;
      }
    }
    cout<<v[0][h-1][0][w-1][0]<<' '<<v[0][h-1][0][w-1][1]<<'\n';
  }
}
accuracy: 1
time_ms: 90
memory_kb: 11472
final_rank: 2

code_snippet: #include<bits/stdc++.h>
// #include<atcoder/all>
// #include<boost/multiprecision/cpp_int.hpp>

using namespace std;
// using namespace atcoder;
// using bint = boost::multiprecision::cpp_int;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<ll,ll>;
using vi = vector<ll>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using ve = vector<vector<int>>;
using vb = vector<bool>;
using vvb = vector<vb>;
#define rep(i,n) for(ll i = 0;i < (ll)n;i++)
#define ALL(x) (x).begin(),(x).end()
#define sz(c) ((ll)(c).size())
#define LB(A,x) (int)(lower_bound(A.begin(),A.end(),x)-A.begin())
#define UB(A,x) (int)(upper_bound(A.begin(),A.end(),x)-A.begin())
// #define MOD 1000000007
#define MOD 998244353
template<typename T>using min_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<typename T>ostream&operator<<(ostream&os,vector<T>&v){for(int i = 0;i < v.size();i++)os<<v[i]<<(i+1!=v.size()?" ":"");return os;}
template<typename T>istream&operator>>(istream&is,vector<T>&v){for(T&in:v)is>>in;return is;}
template<typename T1,typename T2>ostream&operator<<(ostream&os,pair<T1,T2>&p){os<<p.first<<" "<<p.second;return os;}
template<typename T1,typename T2>istream&operator>>(istream&is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T> inline bool chmax(T &a,T b){if(a < b){a = b;return true;}return false;}
template<typename T> inline bool chmin(T &a,T b){if(a > b){a = b;return true;}return false;}
ld dist(ld x1,ld y1,ld x2, ld y2){return sqrtl((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}

const ll inf = MOD;

bool solve(){
  int h,w,S;cin >> h >> w >> S;
  if(!h)return false;
  vvi u(h,vi(w));
  rep(i,h)cin >> u[i];
  vvi rui(h+1,vi(w+1));
  rep(i,h)rep(j,w){
    rui[i+1][j+1] = rui[i+1][j] + rui[i][j+1] - rui[i][j] + u[i][j];
  }
  // l,r,u,d -> {group,max_juyo}
  map<tuple<int,int,int,int>,P> mem;
  // l r [)
  // u d [)
  auto calc = [&](int l,int r,int u,int d){
    return rui[d][r]-rui[d][l]-rui[u][r] + rui[u][l];
  };
  int tae = -S;// 各グループはtae以上
  rep(i,h)rep(j,w)tae += u[i][j];
  auto sub = [&](auto &sub,int l,int r,int u,int d)->P{
    if(mem.count(make_tuple(l,r,u,d)))return mem[make_tuple(l,r,u,d)];
    ll gr = 1,mn = calc(l,r,u,d);
    for(int m = l+1;m < r;m++){
      if(calc(l,m,u,d) >= tae && calc(m,r,u,d) >= tae){
        auto [g1,j1] = sub(sub,l,m,u,d);
        auto [g2,j2] = sub(sub,m,r,u,d);
        if(g1+g2 > gr){
          gr = g1+g2;mn = min(j1,j2);
        }else if(g1+g2 == gr)chmax(mn,min(j1,j2));
      }
    }
    for(int m = u+1;m < d;m++){
      if(calc(l,r,u,m) >= tae && calc(l,r,m,d) >= tae){
        auto [g1,j1] = sub(sub,l,r,u,m);
        auto [g2,j2] = sub(sub,l,r,m,d);
        if(g1+g2 > gr){
          gr = g1+g2;mn = min(j1,j2);
        }else if(g1+g2 == gr)chmax(mn,min(j1,j2));
      }
    }
    return mem[make_tuple(l,r,u,d)] = make_pair(gr,mn);
  };
  P res = sub(sub,0,w,0,h);
  res.second = S - (rui[h][w]-res.second);
  cout << res << "\n";
  return true;
}

int main(){
  
  ios_base::sync_with_stdio(0), cin.tie(0);
  while(solve());
  

  return 0;
}
accuracy: 1
time_ms: 4260
memory_kb: 25148
final_rank: 17

code_snippet: #ifdef t9unkubj
#include"debug.cpp"
//#include"template_no_debug.h"
#else 
#define dbg(...) 199958
#endif

#undef _GLIBCXX_DEBUG
#pragma GCC optimize("O3")
using namespace std;
#include<bits/stdc++.h>
using ll=long long;
using ull=unsigned long long;
template<class T>using vc=vector<T>;
template<class T>using vvc=vc<vc<T>>;
#define rep(i,n) for(ll i=0;i<(ll)(n);i++)
#define REP(i,j,n) for(ll i=(j);i<(ll)(n);i++)
#define DREP(i,n,m) for(ll i=(n);i>=(m);i--)
#define drep(i,n) for(ll i=((n)-1);i>=0;i--)
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
template<class T,class F>
bool chmin(T &x, F y){
    if(x>y){
        x=y;
        return true;
    }
    return false;
}
template<class T, class F>
bool chmax(T &x, F y){
    if(x<y){
        x=y;
        return true;
    }
    return false;
}
double pass_time=0;
const int N=33;
//group 余り
pair<int,int> dp[N][N][N][N];
int seen[N][N][N][N];
void solve(){
while(1){
    rep(i,N)rep(j,N)rep(k,N)rep(l,N)dp[i][j][k][l]={0,0},seen[i][j][k][l]=0;
    int h,w,s;
    cin>>h>>w>>s;
    if(h==0&&w==0&&s==0)break;
    vvc<int>u(h,vc<int>(w));
    int al=0;
    rep(i,h)rep(j,w)cin>>u[i][j],al+=u[i][j];
    vvc<int>pre(h+1,vc<int>(w+1));
    rep(i,h)rep(j,w)pre[i+1][j+1]=u[i][j];
    rep(i,h)rep(j,w+1)pre[i+1][j]+=pre[i][j];
    rep(i,h+1)rep(j,w)pre[i][j+1]+=pre[i][j];
    int least=al-s;
    //グループはleast以上
    auto dfs=[&](auto&dfs,int a,int b,int c,int d)->pair<int,int>{
        if(seen[a][b][c][d])return dp[a][b][c][d];
        seen[a][b][c][d]=1;
        dp[a][b][c][d]=make_pair(-1e5,-1);
        REP(i,a+1,b){
            auto p1=dfs(dfs,a,i,c,d);
            auto p2=dfs(dfs,i,b,c,d);
            chmax(dp[a][b][c][d],make_pair(p1.first+p2.first,min(p1.second,p2.second)));
        }
        REP(i,c+1,d){
            auto p1=dfs(dfs,a,b,c,i);
            auto p2=dfs(dfs,a,b,i,d);
            chmax(dp[a][b][c][d],make_pair(p1.first+p2.first,min(p1.second,p2.second)));
        }
        int thi=pre[b][d]-pre[b][c]-pre[a][d]+pre[a][c];
        if(thi>=least){
            chmax(dp[a][b][c][d],make_pair(1,thi-least));
        }
        
        return dp[a][b][c][d];
    };
    dfs(dfs,0,h,0,w);
    cout<<dp[0][h][0][w].first<<" "<<dp[0][h][0][w].second<<endl;
}
}
signed main(){
#ifdef t9unkubj
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
    cin.tie(0)->sync_with_stdio(0);
    pass_time=clock();
    int t=1;
    //cin>>t;
    while(t--)solve();
    pass_time=clock()-pass_time;
    dbg(pass_time/CLOCKS_PER_SEC);
}
accuracy: 1
time_ms: 160
memory_kb: 17328
final_rank: 14

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

int N, M, S, X;
int A[32][32];
pair<int,int> DP[33][33][33][33];
bool memo[33][33][33][33];

pair<int,int> DFS(int LX, int RX, int LY, int RY) {
    if (memo[LX][RX][LY][RY]) return DP[LX][RX][LY][RY];
    int COUNT = 0;
    rep(i,LX,RX) rep(j,LY,RY) COUNT += A[i][j];
    if (COUNT < X) {
        memo[LX][RX][LY][RY] = true;
        return DP[LX][RX][LY][RY] = {-1,-1};
    }
    DP[LX][RX][LY][RY] = {1,COUNT-X};
    rep(MX,LX+1,RX) {
        pair<int,int> P1 = DFS(LX,MX,LY,RY), P2 = DFS(MX,RX,LY,RY);
        if (P1.first == -1 || P2.first == -1) continue;
        if (P1.first + P2.first > DP[LX][RX][LY][RY].first || (P1.first + P2.first == DP[LX][RX][LY][RY].first && min(P1.second, P2.second) > DP[LX][RX][LY][RY].second)) {
            DP[LX][RX][LY][RY] = {P1.first + P2.first, min(P1.second, P2.second)};
        }
    }
    rep(MY,LY+1,RY) {
        pair<int,int> P1 = DFS(LX,RX,LY,MY), P2 = DFS(LX,RX,MY,RY);
        if (P1.first + P2.first > DP[LX][RX][LY][RY].first || (P1.first + P2.first == DP[LX][RX][LY][RY].first && min(P1.second, P2.second) > DP[LX][RX][LY][RY].second)) {
            DP[LX][RX][LY][RY] = {P1.first + P2.first, min(P1.second, P2.second)};
        }
    }
    memo[LX][RX][LY][RY] = true;
    return DP[LX][RX][LY][RY];
}

int main() {
while(1) {
    cin>> N >> M >> S;
    if (N == 0) return 0;
    rep(i,0,N+1) rep(j,0,N+1) rep(k,0,M+1) rep(l,0,M+1) memo[i][j][k][l] = false;
    int COUNT = 0;
    rep(i,0,N) rep(j,0,M) cin >> A[i][j], COUNT += A[i][j];
    X = COUNT - S;
    pair<int,int> ANS = DFS(0,N,0,M);
    cout << ANS.first << ' ' << ANS.second << endl;
}
}
accuracy: 1
time_ms: 220
memory_kb: 13640
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
#define rep(i, a, b) for(ll i = a; i < b; ++i)
#define rrep(i, a, b) for(ll i = a; i >= b; --i)
constexpr ll inf = 4e18;
struct SetupIO {
    SetupIO() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout << fixed << setprecision(30);
    }
} setup_io;
template <typename T>
struct CumulativeSum2D {
    CumulativeSum2D(int H, int W)
        : h(H), w(W), data(H + 1, vector<T>(W + 1, 0)) {}
    void add(int i, int j, const T& x) {
        assert(0 <= i and i < h);
        assert(0 <= j and j < w);
        data[i + 1][j + 1] += x;
    }
    void init() {
        for(int i = 1; i < (int)data.size(); ++i) {
            for(int j = 1; j < (int)data[i].size(); ++j) {
                data[i][j] += data[i][j - 1] + data[i - 1][j] - data[i - 1][j - 1];
            }
        }
    }
    T sum(int li, int lj, int ri, int rj) {
        assert(0 <= li and li <= ri and ri <= h);
        assert(0 <= lj and lj <= rj and rj <= w);
        return data[ri][rj] - data[li][rj] - data[ri][lj] + data[li][lj];
    }
    T get(int i, int j) {
        assert(0 <= i and i < h);
        assert(0 <= j and j < w);
        return data[i + 1][j + 1] - data[i][j + 1] - data[i + 1][j] + data[i][j];
    }

   private:
    int h, w;
    vector<vector<T>> data;
};
int main(void) {
    while(true) {
        int h, w, s;
        cin >> h >> w >> s;
        if(h == 0 and w == 0 and s == 0) break;
        vector<vector<int>> u(h, vector<int>(w));
        CumulativeSum2D<int> cum(h, w);
        rep(i, 0, h) {
            rep(j, 0, w) {
                cin >> u[i][j];
                cum.add(i, j, u[i][j]);
            }
        }
        cum.init();
        int diff = cum.sum(0, 0, h, w) - s;
        vector<vector<vector<vector<pair<int, int>>>>> dp(h + 1, vector<vector<vector<pair<int, int>>>>(h + 1, vector<vector<pair<int, int>>>(w + 1, vector<pair<int, int>>(w + 1, {-1, -1}))));
        auto dfs = [&](auto& dfs, int li, int ri, int lj, int rj) -> pair<int, int> {
            if(dp[li][ri][lj][rj] != pair<int, int>{-1, -1}) return dp[li][ri][lj][rj];
            pair<int, int> res = {1, cum.sum(li, lj, ri, rj) - diff};
            rep(i, li + 1, ri) {
                if(cum.sum(li, lj, i, rj) >= diff and cum.sum(i, lj, ri, rj) >= diff) {
                    pair<int, int> res1 = dfs(dfs, li, i, lj, rj);
                    pair<int, int> res2 = dfs(dfs, i, ri, lj, rj);
                    if(res1.first + res2.first > res.first) {
                        res = {res1.first + res2.first, min(res1.second, res2.second)};
                    } else if(res1.first + res2.first == res.first and min(res1.second, res2.second) > res.second) {
                        res = {res1.first + res2.first, min(res1.second, res2.second)};
                    }
                }
            }
            rep(j, lj + 1, rj) {
                if(cum.sum(li, lj, ri, j) >= diff and cum.sum(li, j, ri, rj) >= diff) {
                    pair<int, int> res1 = dfs(dfs, li, ri, lj, j);
                    pair<int, int> res2 = dfs(dfs, li, ri, j, rj);
                    if(res1.first + res2.first > res.first) {
                        res = {res1.first + res2.first, min(res1.second, res2.second)};
                    } else if(res1.first + res2.first == res.first and min(res1.second, res2.second) > res.second) {
                        res = {res1.first + res2.first, min(res1.second, res2.second)};
                    }
                }
            }
            return dp[li][ri][lj][rj] = res;
        };
        pair<int, int> ans = dfs(dfs, 0, h, 0, w);
        cout << ans.first << ' ' << ans.second << '\n';
    }
}
accuracy: 1
time_ms: 260
memory_kb: 13996
final_rank: 7

code_snippet: #include<iostream>
using namespace std;
const int INF=1e9;
const pair<int,int>init_val=make_pair(-INF,-INF);
int H,W,S,A[32][32];
int sum;
pair<int,int>memo[33][33][33][33];
bool vis[33][33][33][33];
bool init()
{
    cin>>H>>W>>S;
    if(H==0&&W==0&&S==0)return false;
    sum=0;
    for(int i=0;i<H;i++)for(int j=0;j<W;j++)cin>>A[i][j],sum+=A[i][j];
    for(int r1=0;r1<=H;r1++)for(int r2=0;r2<=H;r2++)
    {
        for(int c1=0;c1<=W;c1++)for(int c2=0;c2<=W;c2++)
        {
            vis[r1][r2][c1][c2]=false;
            memo[r1][r2][c1][c2]=init_val;
        }
    }
    return true;
}
pair<int,int>dfs(int r1, int r2, int c1, int c2)
{
    if(vis[r1][r2][c1][c2])return memo[r1][r2][c1][c2];
    vis[r1][r2][c1][c2]=true;
    int cur_sum=0;
    for(int i=r1;i<r2;i++)for(int j=c1;j<c2;j++)cur_sum+=A[i][j];
    if(sum-cur_sum>S)return init_val;
    memo[r1][r2][c1][c2]=make_pair(1,S-(sum-cur_sum));
    for(int i=r1+1;i<r2;i++)
    {
        auto[p1,p2]=dfs(r1,i,c1,c2);
        auto[q1,q2]=dfs(i,r2,c1,c2);
        memo[r1][r2][c1][c2]=max(memo[r1][r2][c1][c2],make_pair(p1+q1,min(p2,q2)));
    }
    for(int j=c1+1;j<c2;j++)
    {
        auto[p1,p2]=dfs(r1,r2,c1,j);
        auto[q1,q2]=dfs(r1,r2,j,c2);
        memo[r1][r2][c1][c2]=max(memo[r1][r2][c1][c2],make_pair(p1+q1,min(p2,q2)));
    }
    return memo[r1][r2][c1][c2];
}
bool solve()
{
    if(!init())return false;
    auto[p1,p2]=dfs(0,H,0,W);
    cout<<p1<<' '<<p2<<endl;
    return true;
}
int main(){while(solve()){}}
accuracy: 1
time_ms: 220
memory_kb: 13796
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for (int i = a; i < n; i++)
#define rrep(i, a, n) for (int i = a; i >= n; i--)
#define inr(l, x, r) (l <= x && x < r)
#define ll long long
#define ld long double
#define pii pair<int,int>

constexpr int IINF = 1001001001;
constexpr ll INF = 9e18;

template <class t, class u>
void chmax(t& a, u b) {
    if (a < b) a = b;
}
template <class t, class u>
void chmin(t& a, u b) {
    if (b < a) a = b;
}

int main() {
    while(1){
        int h, w, s;cin >> h >> w >> s;
        if(h+w+s==0) return 0;
        vector<vector<int>> a(h, vector<int>(w));
        rep(i, 0, h)rep(j, 0, w) cin >> a[i][j];
        vector<vector<int>> sum(h+1, vector<int>(w+1,0));
        rep(i, 0, h){
            rep(j, 0, w){
                sum[i+1][j+1] = a[i][j]+sum[i+1][j]+sum[i][j+1]-sum[i][j]; 
            }
        }
        // [u, d), [l, r)
        auto calcsum = [&](int u, int d, int l, int r)->int{
            return sum[d][r]-sum[d][l]-sum[u][r]+sum[u][l];
        };
        vector<vector<vector<vector<pii>>>> dp(h,vector<vector<vector<pii>>>(h+1,vector<vector<pii>>(w,vector<pii>(w+1,{-1,-1}))));
        int total = sum[h][w];

        rep(hw, 1, h+1)rep(ww, 1, w+1)rep(u, 0, h)rep(l, 0, w){
            int d = u+hw, r = l + ww;
            if(d > h || r > w) continue;
            if(total-calcsum(u, d, l, r)<=s) dp[u][d][l][r] = {1,s-total+calcsum(u, d, l, r)};
            rep(mid, u+1, d){
                pii udp = dp[u][mid][l][r], ddp = dp[mid][d][l][r];
                if(udp.first == -1 || ddp.first ==  -1) continue;
                chmax(dp[u][d][l][r],make_pair(udp.first+ddp.first,min(udp.second,ddp.second)));
            }
            rep(mid, l+1, r){
                pii ldp = dp[u][d][l][mid], rdp = dp[u][d][mid][r];
                if(ldp.first == -1 || rdp.first ==  -1) continue;
                chmax(dp[u][d][l][r],make_pair(ldp.first+rdp.first,min(ldp.second,rdp.second)));
            }
        }

        pii ans = dp[0][h][0][w];
        cout << ans.first << ' ' << ans.second << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 13252
final_rank: 4

code_snippet: #include <bits/stdc++.h>

std::ostream& operator<<(std::ostream& os, const std::pair<int, int>& P) {
    std::cout << '(' << P.first << ',' << P.second << ')';
    return os;
}

// 特殊な演算に注意
std::pair<int, int> operator+(const std::pair<int, int>& L, const std::pair<int, int>& R) {
    return std::pair<int, int>{ L.first + R.first, std::max(L.second, R.second) };
}

void chmax(std::pair<int, int>& L, const std::pair<int, int>& R) {
    if (L.first < R.first) L = R;
    else if (L.first == R.first and L.second > R.second) L = R;
}

bool solve() {
    int H, W, S;
    std::cin >> H >> W >> S;
    if (H == 0 and W == 0 and S == 0) return false;
    std::vector U(H, std::vector<int>(W));
    for (auto& u : U) {
        for (auto& x : u) std::cin >> x;
    }
    std::vector sum(H + 1, std::vector<int>(W + 1));
    for (int i{1} ; i <= H ; i++) {
        for (int j{1} ; j <= W ; j++) {
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + U[i - 1][j - 1];
        }
    }
    auto query{[&](int l, int r, int u, int d) -> int {
        assert(0 <= l and l < r and r <= H);
        assert(0 <= u and u < d and d <= W);
        return sum[r][d] - sum[r][u] - sum[l][d] + sum[l][u];
    }};
    int all{sum[H][W]};
    std::vector dp(H + 1, std::vector(H + 1, std::vector(W + 1, std::vector<std::pair<int, int>>(W + 1, std::pair<int, int>(-1, -1)))));
    const std::pair<int, int> INVALID{-100, -100};
    auto rec{[&](auto rec, int l, int r, int u, int d) -> std::pair<int, int> {
        //std::cout << "call " << l << ' ' << r << ' ' << u << ' ' << d << std::endl;
        std::pair<int, int>& key{dp[l][r][u][d]};
        if (key != std::pair<int, int>{-1, -1}) return key;
        if (all - query(l, r, u, d) > S) {
            return key = INVALID;
        }
        key = std::pair{ 1, (all - query(l, r, u, d)) };
        for (int mid{l + 1} ; mid < r ; mid++) {
            auto front{rec(rec, l, mid, u, d)};
            auto back{rec(rec, mid, r, u, d)};
            if (front == INVALID or back == INVALID) continue;
            auto combined{front + back};
            chmax(key, combined);
        }
        for (int mid{u + 1} ; mid < d ; mid++) {
            auto front{rec(rec, l, r, u, mid)};
            auto back{rec(rec, l, r, mid, d)};
            if (front == INVALID or back == INVALID) continue;
            auto combined{front + back};
            chmax(key, combined);
        }
        //std::cout << l << ' ' << r << ' ' << u << ' ' << d << " is " << key << std::endl;
        return key;
    }};
    auto ans{rec(rec, 0, H, 0, W)};
    std::cout << ans.first << ' ' << S - ans.second << '\n';
    return true;
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    while (solve()) ;
}
accuracy: 1
time_ms: 340
memory_kb: 14032
final_rank: 12

code_snippet: // (⁠◕⁠ᴗ⁠◕⁠✿⁠)

// #pragma GCC target("avx2")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define srep(i, s, n) for (ll i = s; i < (n); i++)
#define len(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
template<typename T> using vc = vector<T>;
template<typename T> using vv = vc<vc<T>>;
template<typename T> using vvv = vv<vc<T>>;
using vi = vc<int>;using vvi = vv<int>; using vvvi = vv<vi>;
using ll = long long;using vl = vc<ll>;using vvl = vv<ll>; using vvvl = vv<vl>;
using ld = long double; using vld = vc<ld>; using vvld = vc<vld>; using vvvld = vc<vvld>;
using uint = unsigned int;
using ull = unsigned long long;
const ld pi = 3.141592653589793;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
// const ll mod = 1000000007;
const ll mod = 998244353;
inline bool inside(ll y, ll x, ll H, ll W) {return 0 <= (y) and (y) < (H) and 0 <= (x) and (x) < (W); }

#define debug(var)  do{std::cout << #var << " : \n";view(var);}while(0)
template<typename T> void view(T e){cout << e << endl;}
template<typename T> void view(const vc<T>& v){for(const auto& e : v){ cout << e << " "; } cout << endl;}
template<typename T> void view(const vv<T>& vv){ for(const auto& v : vv){ view(v); } }

pair<int, int> solve(int H, int W, int S){
    vvi U(H, vi (W)); rep(i, H) rep(j, W) cin >> U[i][j];
    vv<vv<pair<int, int>>> memo(H, vvv<pair<int, int>>(W, vv<pair<int, int>>(H + 1, vc<pair<int, int>>(W + 1, {-1, -1}))));
    vvi cmsm(H + 1, vi(W + 1, 0));
    rep(i, H) rep(j, W) cmsm[i + 1][j + 1] = U[i][j] + cmsm[i + 1][j] + cmsm[i][j + 1] - cmsm[i][j];
    int sm = cmsm[H][W];
    function<pair<int, int>(int, int, int, int)> dp = [&](int x1, int y1, int x2, int y2) -> pair<int, int>{
        if (memo[x1][y1][x2][y2].first != -1) return memo[x1][y1][x2][y2];
        int p = S - (sm - (cmsm[x2][y2] - cmsm[x1][y2] - cmsm[x2][y1] + cmsm[x1][y1]));
        if (p < 0) return {-1, -1};
        int div = 1;
        for (int h = x1 + 1; h < x2; h++){
            auto [d1, p1] = dp(x1, y1, h, y2);
            auto [d2, p2] = dp(h, y1, x2, y2);
            if (d1 == -1 || d2 == -1) continue;
            if (div < d1 + d2){
                div = d1 + d2;
                p = min(p1, p2);
            }else if (div == d1 + d2) p = max(p, min(p1, p2));
        }
        for (int w = y1 + 1; w < y2; w++){
            auto [d1, p1] = dp(x1, y1, x2, w);
            auto [d2, p2] = dp(x1, w, x2, y2);
            if (d1 == -1 || d2 == -1) continue;
            if (div < d1 + d2){
                div = d1 + d2;
                p = min(p1, p2);
            }else if (div == d1 + d2) p = max(p, min(p1, p2));
        }
        return memo[x1][y1][x2][y2] = {div, p};
    };
    return dp(0, 0, H, W);
}

int main(){
    vc<pair<int, int>> ans;
    while (true){
        int H, W, S; cin >> H >> W >> S;
        if (H == 0) break;
        ans.push_back(solve(H, W, S));
    }
    for (auto x : ans) cout << x.first << " " << x.second << endl;
}
accuracy: 1
time_ms: 400
memory_kb: 13332
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pi;
int h, w, s, wa, u[33][33];
pi memo[33][33][33][33];
int rui(int y1, int x1, int y2, int x2){
    return u[y2][x2]-u[y1-1][x2]-u[y2][x1-1]+u[y1-1][x1-1];
}
pi dp(int y1, int x1, int y2, int x2){
    if(memo[y1][x1][y2][x2].first!=-1) return memo[y1][x1][y2][x2];
    pi res = pi(1, s-(wa-rui(y1, x1, y2, x2)));
    for(int i=x1;i<x2;i++){
        if(wa-rui(y1, x1, y2, i)>s || wa-rui(y1, i+1, y2, x2)>s) continue;
        pi p1 = dp(y1, x1, y2, i);
        pi p2 = dp(y1, i+1, y2, x2);
        res = max(res, pi(p1.first+p2.first, min(p1.second, p2.second)));
    }
    for(int i=y1;i<y2;i++){
        if(wa-rui(y1, x1, i, x2)>s || wa-rui(i+1, x1, y2, x2)>s) continue;
        pi p1 = dp(y1, x1, i, x2);
        pi p2 = dp(i+1, x1, y2, x2);
        res = max(res, pi(p1.first+p2.first, min(p1.second,p2.second)));
    }
    return memo[y1][x1][y2][x2] = res;
}
int main(){
    while(cin >> h >> w >> s, h){
        memset(u, 0, sizeof(u));
        for(int i=1;i<=h;i++){
            for(int j=1;j<=w;j++){
                cin >> u[i][j];
                u[i][j] += u[i-1][j]+u[i][j-1]-u[i-1][j-1];
            }
        }
        wa = u[h][w];
        fill_n(***memo, 33*33*33*33, pi(-1, -1));
        pi ans = dp(1, 1, h, w);
        cout << ans.first << " " << ans.second << endl;
    }
    return(0);
}
accuracy: 1
time_ms: 220
memory_kb: 12344
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

struct Sum2D {
    int h;
    int w;
    vector<vector<int>> sum;

    Sum2D(const vector<vector<int>>& vec) : h(vec.size()), w(vec.front().size()) {
        sum.resize(h + 1, vector<int>(w + 1));
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                sum[i + 1][j + 1] = vec[i][j];
            }
        }

        for (int i = 0; i <= h; i++) {
            for (int j = 0; j < w; j++) {
                sum[i][j + 1] += sum[i][j];
            }
        }
        for (int i = 0; i < h; i++) {
            for (int j = 0; j <= w; j++) {
                sum[i + 1][j] += sum[i][j];
            }
        }
    }
    
    int get(int si, int sj, int ti, int tj) const {
        return sum[ti][tj] + sum[si][sj] - sum[ti][sj] - sum[si][tj];
    }
};

struct Data {
    int size = -1;
    int power = -1;
    Data() = default;
    Data(int size, int power) : size(size), power(power) {}
};

bool operator<(const Data& lhs, const Data& rhs) {
    if (lhs.size == rhs.size) {
        return lhs.power < rhs.power;
    } else {
        return lhs.size < rhs.size;
    }
}

bool operator>(const Data& lhs, const Data& rhs) {
    if (lhs.size == rhs.size) {
        return lhs.power > rhs.power;
    } else {
        return lhs.size > rhs.size;
    }
}

bool operator==(const Data& lhs, const Data& rhs) {
    return lhs.size == rhs.size && lhs.power == rhs.power;
}

bool operator!=(const Data& lhs, const Data& rhs) {
    return !(lhs == rhs);
}

Data operator+(const Data& lhs, const Data& rhs) {
    return Data(lhs.size + rhs.size, min(lhs.power, rhs.power));
}

bool solve() {
    int h, w, s;
    cin >> h >> w >> s;
    if (h == 0) return false;
    vector<vector<int>> u(h, vector<int>(w));
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            cin >> u[i][j];
        }
    }
    Sum2D sum(u);
    int e = sum.get(0, 0, h, w);
//     cerr << e << '\n';
//     return 0;
    
    vector dp(h + 1, vector<vector<vector<Data>>>(w + 1, vector<vector<Data>>(h + 1, vector<Data>(w + 1))));
    Data init;
    auto dfs = [&](auto dfs, int si, int sj, int ti, int tj) -> Data {
        if (dp[si][sj][ti][tj] != init) return dp[si][sj][ti][tj];
        if (e - sum.get(si, sj, ti, tj) > s) {
            return dp[si][sj][ti][tj] = init;
        }
        Data res(1, s - (e - sum.get(si, sj, ti, tj)));
        for (int i = si + 1; i < ti; i++) {
            Data data1 = dfs(dfs, si, sj, i, tj);
            Data data2 = dfs(dfs, i, sj, ti, tj);
            if (data1 == init || data2 == init) continue;
            res = max(res, data1 + data2);
        }
        for (int j = sj + 1; j < tj; j++) {
            Data data1 = dfs(dfs, si, sj, ti, j);
            Data data2 = dfs(dfs, si, j, ti, tj);
            if (data1 == init || data2 == init) continue;
            res = max(res, data1 + data2);
        }
        return dp[si][sj][ti][tj] = res;
    };
    auto [sz, power] = dfs(dfs, 0, 0, h, w);
    cout << sz << ' ' << power << '\n';
    return true;
}

int main() {
    while (solve());
}
accuracy: 1
time_ms: 360
memory_kb: 13956
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <typename T>
class CumlativeSum2D {
    private:
        const int h, w;
        std::vector<std::vector<T>> data;
        bool is_build = false;

    public:
        CumlativeSum2D(const std::vector<std::vector<T>> &vec) : h(vec.size()), w(vec.front().size()) {
            data.resize(h + 2, std::vector<T>(w + 2, 0));
            for (int i = 0 ; i < h ; i++) {
                for (int j = 0 ; j < w ; j++) {
                    data[i + 1][j + 1] = vec[i][j];
                }
            }
        }

        void build() {
            assert(!is_build);
            for (int i = 0 ; i < h ; i++) {
                for (int j = 0 ; j < w ; j++) {
                    data[i + 1][j + 1] += data[i][j + 1] + data[i + 1][j] - data[i][j];
                }
            }
            is_build = true;
        }

        T get_sum(const int i1, const int j1, const int i2, const int j2) {
            assert(0 <= i1 && i1 < h && 0 <= j1 && j1 < w);
            assert(0 <= i2 && i2 <= h && 0 <= j2 && j2 <= w);
            assert(i1 <= i2 && j1 <= j2);
            assert(is_build);
            return data[i2][j2] + data[i1][j1] - data[i2][j1] - data[i1][j2];
        }
};

struct info {
    int part, yobi;
    bool can;
    info() : part(-1), yobi(-1), can(false) {}
    info(int p, int y, bool c) : part(p), yobi(y), can(c) {}
};

bool solve() {
    int h, w, s; cin >> h >> w >> s;
    if (h == 0) return false;

    vector A(h, vector<int>(w));
    for (auto& a : A) for (auto& x : a) cin >> x;

    CumlativeSum2D S(A);
    S.build();

    int allsum = S.get_sum(0, 0, h, w);

    vector dp(h + 1, vector(h + 1, vector(w + 1, vector(w + 1, info()))));
    vector used(h + 1, vector(h + 1, vector(w + 1, vector(w + 1, false)))); 

    auto rec = [&](auto rec, int y1, int y2, int x1, int x2) -> info {
        if (used[y1][y2][x1][x2]) return dp[y1][y2][x1][x2];
        used[y1][y2][x1][x2] = true;

        info& res = dp[y1][y2][x1][x2];

        if (allsum - S.get_sum(y1, x1, y2, x2) > s) return res = info();

        int part = 1;
        int yobi = s - (allsum - S.get_sum(y1, x1, y2, x2));
        assert(yobi >= 0);

        for (int m = y1 + 1 ; m < y2 ; m++) {
            info top = rec(rec, y1, m, x1, x2);
            info down = rec(rec, m, y2, x1, x2);
            if (!top.can or !down.can) continue;
            if (part < top.part + down.part) {
                part = top.part + down.part;
                yobi = min(top.yobi, down.yobi);
            }
            else if (part == top.part + down.part) {
                yobi = max(yobi, min(top.yobi, down.yobi));
            }
        }

        for (int m = x1 + 1 ; m < x2 ; m++) {
            info top = rec(rec, y1, y2, x1, m);
            info down = rec(rec, y1, y2, m, x2);
            if (!top.can or !down.can) continue;
            if (part < top.part + down.part) {
                part = top.part + down.part;
                yobi = min(top.yobi, down.yobi);
            }
            else if (part == top.part + down.part) {
                yobi = max(yobi, min(top.yobi, down.yobi));
            }
        }

        return res = info(part, yobi, true);
    };

    info ans = rec(rec, 0, h, 0, w);

    cout << ans.part << ' ' << ans.yobi << endl;

    return true;
}

int main() {
    while (solve()) ;
}
accuracy: 1
time_ms: 460
memory_kb: 21188
final_rank: 15