#include<bits/stdc++.h>
#define MAXN 0x7f7f7f7f
#define re register
using namespace std;
struct Q1{
int abs;
int ord;
};
struct Q2{
int left;
int right;
int size;
}C1[501];
int m,n;
int altitude[501][501];
int num[501][501];
bool visit[501][501];
queue<Q1> bfs;
set<int> S1;
vector<int> amount;
template<typename T>inline void qread(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
inline void search(int x){
Q1 q={1,x};
bfs.push(q);
visit[1][x]=true;
while(!bfs.empty()){
int a=bfs.front().abs;
int b=bfs.front().ord;
bfs.pop();
if(visit[a-1][b]==false&&altitude[a-1][b]<altitude[a][b]){
visit[a-1][b]=true;
Q1 t={a-1,b};
bfs.push(t);
}
if(visit[a+1][b]==false&&altitude[a+1][b]<altitude[a][b]){
visit[a+1][b]=true;
Q1 t={a+1,b};
bfs.push(t);
}
if(visit[a][b-1]==false&&altitude[a][b-1]<altitude[a][b]){
visit[a][b-1]=true;
Q1 t={a,b-1};
bfs.push(t);
}
if(visit[a][b+1]==false&&altitude[a][b+1]<altitude[a][b]){
visit[a][b+1]=true;
Q1 t={a,b+1};
bfs.push(t);
}
}
return;
}
inline void seize(int x){
int ton=0;
for(re int i=1;i<=n;i++){
if(visit[m][i]==true){
ton++;
num[x][ton]=i;
}
}
amount.push_back(ton);
return;
}
inline bool cmp(const Q2 &x,const Q2 &y){
if(x.left<y.left) return 1;
else if(x.left==y.left&&x.size>y.size) return 1;
else return 0;
}
inline void check(int x){
if(C1[x].left==0||C1[x].right==0){
C1[x].left=MAXN;
C1[x].right=MAXN;
C1[x].right=MAXN;
}
return;
}
inline int cover(){
for(re int i=1;i<=n;i++){
C1[i].left=num[i][1];
C1[i].right=num[i][amount[i]];
C1[i].size=C1[i].right-C1[i].left+1;
}
for(re int i=1;i<=n;i++){
check(i);
}
stable_sort(C1+1,C1+n+1,cmp);
int ton1=C1[1].right,ton2=0,ans=1;
if(ton1==n) return ans;
else{
while(1){
for(re int j=1;j<=n;j++){
if(C1[j].left<=ton1+1&&C1[j].right>ton2){
ton2=C1[j].right;
}
}
ans++;
if(ton2==n) return ans;
else{
ton1=ton2;
continue;
}
}
}
}
int main(){
qread(m);qread(n);
for(re int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
qread(altitude[i][j]);
}
}
for(re int i=1;i<=m;i++){
altitude[i][0]=MAXN;
}
for(re int i=1;i<=n;i++){
altitude[0][i]=MAXN;
}
for(int i=1;i<=m;i++){
altitude[i][n+1]=MAXN;
}
for(int i=1;i<=n;i++){
altitude[m+1][i]=MAXN;
}
amount.push_back(0);
for(re int i=1;i<=n;i++){
search(i);
seize(i);
memset(visit,false,sizeof(visit));
}
for(re int i=1;i<=n;i++){
for(re int j=1;j<=amount[i];j++){
S1.insert(num[i][j]);
}
}
if(S1.size()<n){
cout<<"0"<<'\n'<<n-S1.size();
return 0;
}
else{
cout<<"1"<<'\n'<<cover();
return 0;
}
}