zoukankan      html  css  js  c++  java
  • ZOJ Saddle Point 数学思维题

    http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5564

     

    根据它的定义是行最小,列最大。

    可以证明鞍点是唯一的。

    单独考虑每一个元素的贡献,它能成为鞍点的情况有:

    1、在这一行中,<= a[i][j]的元素肯定要删除,那么剩下k1个大于他a[i][j]的,当然a[i][j]本身不能删除

    2、在这一列中,>= a[i][j]的元素肯定要删除,那么剩下k2个小于a[i][j]的,当然a[i][j]本身不能删除

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

    也就是要知道a[i][j]在当前行中,有多少个元素比它大,在当前列中,有多少个元素比它小,处理出来即可。

    比赛的时候想到了bit,然后发现好像sort然后二分找即可。

    越学越傻

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 1e6 + 20;
    int c[maxn];
    int lowbit(int x) {
        return x & (-x);
    }
    void upDate(int pos, int val) {
        while (pos <= maxn - 20) {
            c[pos] += val;
            pos += lowbit(pos);
        }
    }
    int query(int pos) {
        int ans = 0;
        while (pos) {
            ans += c[pos];
            pos -= lowbit(pos);
        }
        return ans;
    }
    int a[1000 + 20][1000 + 20];
    int row[1000 + 20][1000 + 20], col[1000 + 20][1000 + 20];
    const int MOD = 1e9 + 7;
    LL quick_pow(LL a, LL b, LL MOD) {
        LL base = a % MOD;
        LL ans = 1;
        while (b) {
            if (b & 1) {
                ans = (ans * base) % MOD;
            }
            base = (base * base) % MOD;
            b >>= 1;
        }
        return ans;
    }
    void work() {
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
                scanf("%d", &a[i][j]);
            }
        }
        memset(c, 0, sizeof c);
        for (int i = 1; i <= n; ++i) {
            if (i != 1) {
                for (int j = 1; j <= m; ++j) {
                    upDate(a[i - 1][j], -1);
                }
            }
            for (int j = 1; j <= m; ++j) {
                upDate(a[i][j], 1);
            }
            for (int j = 1; j <= m; ++j) {
                row[i][j] = m - query(a[i][j]);
            }
        }
        memset(c, 0, sizeof c);
        for (int i = 1; i <= m; ++i) {
            if (i != 1) {
                for (int j = 1; j <= n; ++j) {
                    upDate(a[j][i - 1], -1);
                }
            }
            for (int j = 1; j <= n; ++j) {
                upDate(a[j][i], 1);
            }
            for (int j = 1; j <= n; ++j) {
                col[j][i] = query(a[j][i] - 1);
            }
        }
        LL ans = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= m; ++j) {
    //            printf("[%d %d] ", row[i][j], col[i][j]);
                ans += quick_pow(2, row[i][j], MOD) * quick_pow(2, col[i][j], MOD) % MOD;
                if (ans >= MOD) ans %= MOD;
            }
    //        cout << endl;
        }
    //    cout << endl;
        printf("%lld
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code

    bit跑了990ms。。吓死了。

  • 相关阅读:
    文档01_基础
    文档07_JavaScript_ajax
    文档02_JavaScript
    文档06_JavaScript_面相对象
    文档05_JavaScript_节点
    文档06_Asp.net2.0_01
    文档04_JavaScript_事件
    文档05_多线程
    文档03_JavaScript_函数
    根据日期计算星座
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6686890.html
Copyright © 2011-2022 走看看