#include<iostream>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
static bool adaptive=false;
static const int base=37159,mod=82651;
static const int MAXN=500,MAXM=500;
static long long int tab[MAXN][MAXM];
static int n,m;
static long long int hash1;
static void finish (int status) {
    cout << hash1 << " " << status << endl ;
    exit(0);
}

static int drow[]={ -1, -0, +0, +1 };
static int dcol[]={ -0, -1, +1, +0 };
static bool check_saddle (int row, int col) {
    for (int i=0; i<4; i++) {
        int r=row+drow[i],c=col+dcol[i];
        if ((r<0)||(r>=n)||(c<0)||(c>=m)) continue;
        if (tab[r][c]==0) return false;
        if (tab[r][c]<=tab[row][col]) return false;
    }
    return true;
}
static bool check_adjacent (int row, int col) {
    for (int i=0; i<4; i++) {
        int r=row+drow[i],c=col+dcol[i];
        if ((r<0)||(r>=n)||(c<0)||(c>=m)) continue;
        if (tab[r][c]==0) continue;
        if (check_saddle(r,c)==true) return false;
    }
    return true;
}

static long long int num=1e11,num2=1e6;
static vector <int> perm;

static int cnt=0;
long long int value (int row, int col) {
    row--; col--;
    if ((row<0)||(row>=n)||(col<0)||(col>=m)) finish(-1);
    cnt++;
    if (cnt>n*m) finish(-2);
    if (adaptive==false) return tab[row][col];

    if (tab[row][col]!=0) return tab[row][col];
    set <long long int> vals;
    for (int i=0; i<4; i++) {
        int r=row+drow[i],c=col+dcol[i];
        if ((r<0)||(r>=n)||(c<0)||(c>=m)) continue;
        if (tab[r][c]==0) continue;
        vals.insert(tab[r][c]);
    }
    if (vals.size()==0) tab[row][col]=num, num+=1e11;
    else {
        for (;;) {
            num2--;
            bool flag=false;
            for (auto i : perm) {
                int r=row+drow[i],c=col+dcol[i];
                if ((r<0)||(r>=n)||(c<0)||(c>=m)) continue;
                if (tab[r][c]==0) continue;
                if (vals.count(tab[r][c]-num2)==0) {
                    tab[row][col]=tab[r][c]-num2;
                    if ((check_saddle(row,col)==false)&&(check_adjacent(row,col)==true)) {
                        flag=true;
                        break;
                    }
                }
                if (vals.count(tab[r][c]+num2)==0) {
                    tab[row][col]=tab[r][c]+num2;
                    if ((check_saddle(row,col)==false)&&(check_adjacent(row,col)==true)) {
                        flag=true;
                        break;
                    }
                }
            }
            if (flag==true) break;
            if (num2<8.5e5) break;
        }
    }
    return tab[row][col];
}
extern pair <int, int> find_locmin_point (int, int);
int main () {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cin >> n >> m ;
    hash1*=base; hash1+=n;
    hash1*=base; hash1+=m;
    if (n==-1) {
        vector <int> nums;
        int fact=1;
        for (int i=0; i<4; i++) {
            fact*=(i+1);
            nums.push_back(i);
        }
        m--;
        for (int i=0; i<4; i++) {
            fact/=(3-i+1);
            perm.push_back(nums[m/fact]);
            nums.erase(nums.begin()+m/fact);
            m%=fact;
        }
        n=MAXN;
        m=MAXM;
        adaptive=true;
    }
    else {
        for (int i=0; i<n; i++) {
            for (int j=0; j<m; j++) {
                cin >> tab[i][j] ;
                hash1*=base; hash1+=tab[i][j];
                hash1%=mod;
            }
        }
    }
    auto [r, c]=find_locmin_point(n,m);
    r--; c--;
    if ((r<0)||(r>=n)||(c<0)||(c>=m)) finish(-3);
    if (check_saddle(r,c)==false) finish(-4);
    cout << hash1 << " " << 0 << endl ;
    cout << cnt << endl ;
    return 0;
}
