/*
分析:
简单DP,对每个格子,选次数最多的那个往下推。
考虑不全面,WA了一次。
2012-08-20
*/
分析:
简单DP,对每个格子,选次数最多的那个往下推。
考虑不全面,WA了一次。
2012-08-20
*/
#include"stdio.h"
#include"string.h"
int n,m;
int map[111][111];
struct A
{
int ts;
int ms;
}dp[111][111];
int Judge(int x,int y)
{
if(x<0 || x>=n || y<0 || y>=m) return 1;
return 0;
}
int main()
{
int T;
int i,l;
int t,x_n,y_n;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
for(l=0;l<m;l++)
scanf("%d",&map[i][l]);
memset(dp,0,sizeof(dp));
dp[0][0].ms=1;
for(i=0;i<n;i++)
{
for(l=0;l<m;l++)
{
if(i==n-1 && l==m-1)continue;
if(map[i][l]==0) continue;
if(dp[i][l].ms==0) continue;
t=map[i][l]+1;
x_n=i+map[i][l];
y_n=l;
while(t--)
{
if(x_n==n-1 && y_n==m-1) {x_n--;y_n++;continue;}
if(Judge(x_n,y_n)) {x_n--;y_n++;continue;}
if(dp[i][l].ts+1>dp[x_n][y_n].ts)
{
dp[x_n][y_n].ts=dp[i][l].ts+1;
dp[x_n][y_n].ms=dp[i][l].ms;
}
else if(dp[i][l].ts+1==dp[x_n][y_n].ts) dp[x_n][y_n].ms+=dp[i][l].ms;
x_n--;
y_n++;
}
if(i+l+map[i][l]>n+m-2)
{
if(dp[i][l].ts>dp[n-1][m-1].ts)
{
dp[n-1][m-1].ts=dp[i][l].ts;
dp[n-1][m-1].ms=dp[i][l].ms;
}
else if(dp[i][l].ts==dp[n-1][m-1].ts) dp[n-1][m-1].ms+=dp[i][l].ms;
}
else if(i+l+map[i][l]==n+m-2)
{
if(dp[i][l].ts+1>dp[n-1][m-1].ts)
{
dp[n-1][m-1].ts=dp[i][l].ts+1;
dp[n-1][m-1].ms=dp[i][l].ms;
}
else if(dp[i][l].ts+1==dp[n-1][m-1].ts) dp[n-1][m-1].ms+=dp[i][l].ms;
}
}
}
printf("%d %d\n",dp[n-1][m-1].ts,dp[n-1][m-1].ms);
}
return 0;
}