/*
没想到还有dp的事 只能水部分分了
前几个点可以水过 4,5暴力也可以
先每个临湖点都灌一下水 (可以加剪枝 比旁边小的可以不搜)
统计每个临湖点能灌倒几个临沙漠点 并记录每个临沙漠点是否能灌倒
这样前三个点就好办了 判断可以输出不能全灌到的点
对于剩下的全部能灌倒得 暴力的话是2^n 也就水两个点了
这里如果全部能灌倒 有一个很有用的性质 :
这时每个临水点能灌到的临沙漠点 一定是相邻的一段
简单反证一下吧
假设有两段不是连续的 那么不连续的那个部分一定会被越过去(形象点)
既然越过去了 介于灌水法的定义 也就是说从这个部分周围走却不覆盖
那显然不论从那个点开始灌 都覆盖不了 与题意矛盾 假设不成立
既然连续 那就记录下来 然后开始dp
显然他是个区间dp 一般的状态f[i][j]显然会爆(再加上枚举起点)
所以我们定义状态f[i]表示1-i全部覆盖最少几个临湖点
转移的话 枚举所有的临湖点 如果合法就更新 最后输出
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 510
using namespace std;
int n,m,g[maxn][maxn],sum;
bool f[maxn][maxn],des[maxn];
int xx[5]={0,0,0,1,-1};
int yy[5]={0,1,-1,0,0};
int dp[maxn];
struct node
{
int l,r,num,falg;
}p[maxn];
void Dfs(int x,int y,int k)
{
f[x][y]=1;
if(x==n)
{
des[y]=1;
p[k].falg=1;
p[k].num++;
p[k].l=min(p[k].l,y);
p[k].r=max(p[k].r,y);
}
for(int i=1;i<=4;i++)
{
int nx=x+xx[i];
int ny=y+yy[i];
if(nx>0&&nx<=n&&ny>0&&ny<=m&&f[nx][ny]==0&&g[x][y]>g[nx][ny])
Dfs(nx,ny,k);
}
}
void DP()
{
memset(dp,127/3,sizeof(dp));
dp[0]=0;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
if(!p[j].falg)continue;
if(p[j].l<=i&&p[j].r>=i)dp[i]=min(dp[i],dp[p[j].l-1]+1);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&g[i][j]);
for(int i=1;i<=m;i++)
{
p[i].l=maxn+1;
memset(f,0,sizeof(f));
Dfs(1,i,i);
}
for(int i=1;i<=m;i++)
if(p[i].num==m)
{
printf("1\n1\n");
return 0;
}
for(int i=1;i<=m;i++)
if(des[i])sum++;
if(sum<m)
{
printf("0\n%d\n",m-sum);
return 0;
}
DP();
printf("1\n%d\n",dp[m]);
return 0;
}