ZOJ

来源:互联网 发布:网络推广外包合同 编辑:程序博客网 时间:2024/06/05 04:43

题意:

给定n*m的 矩阵,

选择一行或者若干行,一列或者若干列,构成新的矩阵,问这个矩阵中,满足某个元素是本行最小本列最大的这个性质的所有元素的个数


思路:

题中说了,所有的矩阵的可能性 有 (2^n - 1) * (2^m - 1)中,显然没法枚举;

所以 我们考虑某一个元素,会在那个矩阵中出现,也就是算这个元素满足上面性质时 对答案的贡献值是多少;

这样我们可以找到一个值推一下,他在本行中满足最小这个条件,那本行中比他大的所有值 所在的那一列跟他都可以组合形成矩阵,

同理在这一列中比他小的的所有值所在的哪一行也可以跟他任意组合 形成矩阵

加个快速幂



#include<iostream>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<set>#include<queue>#include<stack>#include<map>#define PI acos(-1.0)#define in freopen("in.txt", "r", stdin)#define out freopen("out.txt", "w", stdout)#define kuaidian ios::sync_with_stdio(0);using namespace std;typedef long long ll;typedef unsigned long long ull;const int maxn = 1e6, maxd = 1000 + 7;const ll mod = 1e9 + 7;const int INF = 0x7f7f7f7f;int n, m;int a[maxd][maxd];int b[maxd][maxd], c[maxd][maxd];ll pow_(ll x, int n) {    ll ans = 1;    while(n) {        if(n&1) ans = (ans*x) % mod;;        x = (x * x) % mod;        n /= 2;    }    return ans;}void solve() {    int anss = 0;    for(int i = 1; i <= n; ++i) {        for(int j = 1; j <= m; ++j) {            int t1 = m - (upper_bound(b[i]+1, b[i]+1+m, a[i][j]) - (b[i]+1) );            int t2 = (lower_bound(c[j]+1, c[j]+1+n, a[i][j]) - (c[j]+1) );            anss = (anss + (pow_(2, t1))*(pow_(2, t2)) ) % mod;        }    }    cout << anss << endl;}int main() {    int 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", &a[i][j]);                b[i][j] = a[i][j];                c[j][i] = a[i][j];            }        }        for(int i = 1; i <= n; ++i) {            sort(b[i]+1, b[i]+1+m);        }        for(int i = 1; i <= m; ++i) {            sort(c[i]+1, c[i]+1+n);        }        solve();    }    return 0;}


原创粉丝点击