Saddle Point


Time Limit: 1 Second      Memory Limit: 131072 KB


Chiaki has an n × m matrix A. Rows are numbered from 1 to n from top to bottom and columns are numbered from 1 to m from left to right. The element in the i-th row and the j-th column is Ai, j.

Let M({i1, i2, ..., is}, {j1, j2, ..., jt}) be the matrix that results from deleting row i1, i2, ..., is and column j1, j2, ..., jt of A and f({i1, i2, ..., is}, {j1, j2, ..., jt}) be the number of saddle points in matrix M({i1, i2, ..., is}, {j1, j2, ..., jt}).

Chiaki would like to find all the value of f({i1, i2, ..., is}, {j1, j2, ..., jt}). As the output may be very large ((2n - 1)(2m - 1) matrix in total), she is only interested in the value

 

Note that a saddle point of a matrix is an element which is both the only largest element in its column and the only smallest element in its row.

Input

There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains four integers n and m (1 ≤ n, m ≤ 1000) -- the number of rows and the number of columns.

Each of the next n lines contains m integer Ai, 1, Ai, 2, ..., Ai, m (1 ≤ Ai, j ≤ 106), where Ai, j is the integer in the i-th row and the j-th column.

It is guaranteed that neither the sum of all n nor the sum of all m exceeds 5000.

Output

For each test case, output an integer denoting the answer.

Sample Input

2
2 2
1 1
1 1
4 5
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20

Sample Output

4
465

题意:

 n*m的矩阵,n*m个点能否在去掉某些行、列的情况下,成为马鞍点(行中最小列中最大的元素(严格大于和小于)),问所有 点能够马鞍点的方式总数。

分析:

这题要换一个角度考虑,我们考虑每一个a[i][j]成为鞍点的贡献值,

 1、这一行中,<= a[i][j]的元素肯定要删除,剩下k1个大于a[i][j],k1个元素便可以随便删除。

2、这一列中,>= a[i][j]的元素肯定要删除,剩下k2个小于a[i][j],k2个元素便可以随便删除;

总之:对于k1个元素,对应着k1列,要么删除,要么不删除,有2^k1种情况,在k2个元素中,对应着k2列,也是要么删除,要么不删除,。有2^k2种情况,相乘就是贡献。

即知道a[i][j]在当前行中,有多少个元素比它大,在当前列中,有多少个元素比它小,处理出来即可。 树状数组或者排序后二分一下都可以做。
 

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 1005;
const int MOD = 1e9+7;
int mat[maxn][maxn];
int row[maxn][maxn], col[maxn][maxn];
ll quick(ll res, ll k)
{
    ll base = res % MOD;
    ll ans = 1;
    while(k)
    {
        if(k&1)
            ans = ans * base % MOD;
        base = (base*base) % MOD;
        k /= 2;
    }
    return ans;
}
int main()
{
    int n, m, T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                scanf("%d", &mat[i][j]);
                row[i][j] = mat[i][j];
                col[j][i] = mat[i][j];
            }
            
        for(int i = 1; i <= n; i++)
            sort(row[i]+1, row[i]+m+1);
            
        for(int i = 1; i <= m; i++)
            sort(col[i]+1, col[i]+n+1);
            
        ll ans = 0;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
            {
                ll t1 = m - (upper_bound(row[i]+1, row[i]+m+1, mat[i][j]) - row[i] - 1);
                ll t2 = lower_bound(col[j]+1, col[j]+n+1, mat[i][j]) - col[j] - 1;
                ans = (ans + quick(2, t1)*quick(2, t2) % MOD) % MOD;
            }
        printf("%lld\n", ans);
    }
    return 0;
}