zoj3955:Saddle Point(想法题)

传送门

题意

给出n*m的矩阵,询问所有子矩阵中鞍点的个数

鞍点定义:在行唯一最小,在列唯一最大

分析

我们遍历每个点,计算该点对于答案的贡献即可。
每个点的贡献为\((2^{numa[i][j]})*(2^{numb[i][j]})\)
numa[i][j]记录第i行大于该点的数个数
numb[i][j]记录第j列小于该点的数个数

trick

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long mod = 1e9+7;
int mp[1010][1010];
long long ans;
int numa[1010][1010],numb[1010][1010];
int t,n,m,a[1010];
long long quick_mod(int a,int p)
{
    long long ret=a,ans=1;
    if(p<0) return 1;
    for(;p;p>>=1,(ret*=ret)%=mod) if(p&1) (ans*=ret)%=mod;
    return ans;
}
int main()
{
    for(scanf("%d",&t);t--;)
    {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) scanf("%d",&mp[i][j]);
        memset(numa,0,sizeof(numa));
        memset(numb,0,sizeof(numb));
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=m;++j) a[j]=mp[i][j];
            sort(a+1,a+1+m);
            for(int j=1;j<=m;++j) numa[i][j]=m-(upper_bound(a+1,a+1+m,mp[i][j])-a-1);
        }
       // for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) printf("%d%c",numa[i][j],j==m?'\n':' ');
        for(int j=1;j<=m;++j)
        {
            for(int i=1;i<=n;++i) a[i]=mp[i][j];
            sort(a+1,a+1+n);
            for(int i=1;i<=n;++i) numb[i][j]=(lower_bound(a+1,a+1+n,mp[i][j])-a-1);
        }
       // for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) printf("%d%c",numb[i][j],j==m?'\n':' ');
        ans=0;
        for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) (ans+=quick_mod(2,numa[i][j])*quick_mod(2,numb[i][j]))%=mod;
        printf("%lld\n",ans);
    }
}
posted @ 2017-04-12 01:00  遗风忘语  阅读(168)  评论(0编辑  收藏  举报