ZOJ3955 Saddle Point 【快速幂】

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

1i1<<isn1j1<<jtm0s<n0t<mf({i1,i2,,is},{j1,j2,,jt})mod(109+7).

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


主要思路是 考虑A[i][j]在多少个子矩阵中能作为 鞍点
A[i][j]在所在行元素中 必须是最小,列中必须最大
那对原矩阵,如果 A[i][k]>A[i][j] ,那第k列可以选择
同理 如果 A[k][j]<A[i][j] ,那第k行是可以选择的
每行每列有(选/不选)2种情况
A[i][j]=2m1k=0(A[i][k]>A[i][j])+n1k=0(A[k][j]<A[i][j])
=0<=i<n,0<=j<m2m1k=0(A[i][k]>A[i][j])+n1k=0(A[k][j]<A[i][j])

所以只需要通过二分找出 A[i][k]>A[i][j]A[k][j]<A[i][j] 的数量进行快速幂再累加即可
O(nmmax(log(n),log(m)))

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<string.h>
#include<math.h>
#include<list>

using namespace std;

#define ll long long
#define pii pair<int,int>
const int inf = 1e9 + 7;

inline int read(){
    int x;
    char ch;
    while(!isdigit(ch=getchar()));
    x=ch-'0';
    while(isdigit(ch=getchar())){
        x=x*10+ch-'0';
    }
    return x;
}

const int N = 1e3+5;
int mat[N][N];
int r[N][N];//r[i][j]=第i行第j个数
int c[N][N];//c[i][j]=第i列的第i个数

int qPow(int a,int n){
    ll ans=1;
    ll t=a;
    while(n){
        if(n&1){
            ans=(ans*t)%inf;
        }
        n>>=1;
        t=(t*t)%inf;
    }
    return ans;
}

int slove(int n,int m){
    for(int i=0;i<n;++i){
        sort(r[i],r[i]+m);
    }
    for(int i=0;i<m;++i){
        sort(c[i],c[i]+n);
    }
    int ans=0;
    for(int i=0;i<n;++i){
        for(int j=0;j<m;++j){
            int rn=(r[i]+m)-upper_bound(r[i],r[i]+m,mat[i][j]);
            int cn=lower_bound(c[j],c[j]+n,mat[i][j])-c[j];
            ans=(ans+qPow(2,rn+cn))%inf;
        }
    }
    return ans;
}

int main()
{
    //freopen("/home/lu/Documents/r.txt","r",stdin);
    //freopen("/home/lu/Documents/w.txt","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;++i){
            for(int j=0;j<m;++j){
                scanf("%d",&mat[i][j]);
                c[j][i]=r[i][j]=mat[i][j];
            }
        }
        printf("%d\n",slove(n,m));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值