zoukankan      html  css  js  c++  java
  • SPOJ MINSUB

    http://www.spoj.com/problems/MINSUB/en/

    题意:给出一个n*m的矩阵M,和一个面积k,要使得M的子矩阵M'的最小元素最大并且面积大于等于k,问子矩阵M'的最小元素最大能是多少,并且求出最大的面积。

    思路:二分一个最小元素x,转化为判断矩阵M里面是否存在一个子矩阵使得这个子矩阵的面积大于等于k并且所有元素都大于x。

    用另一个矩阵,1表示该位置的元素大于等于x,0表示元素小于x。

    转化为判断是否存在一个子矩阵元素为1的面积大于等于k。

    这样可以用到早上学习的单调栈,去维护最大的子矩阵面积。

    像这样,求出最大的矩阵面积。

    如果矩阵面积大于等于k,那么就去找是否有更大的x去满足题意。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define N 1010
     4 struct node {
     5     int pre, suf, val;
     6 } p[N];
     7 int mat[N][N], mp[N][N], h[N][N], n, m, k, square;
     8 
     9 bool check(int x) {
    10     memset(mp, 0, sizeof(mp));
    11     memset(h, 0, sizeof(h));
    12     for(int i = 1; i <= n; i++)
    13         for(int j = 1; j <= m; j++) if(mat[i][j] >= x) mp[i][j] = 1;
    14     square = 0;
    15     for(int i = 1; i <= n; i++) {
    16         stack<node> sta;
    17         for(int j = 1; j <= m; j++) {
    18             if(mp[i][j]) h[i][j] = h[i-1][j] + 1;
    19             p[j] = (node) {1, 1, h[i][j]};
    20         }
    21         sta.push(p[1]);
    22         for(int j = 2; j <= m; j++) {
    23             while(!sta.empty() && sta.top().val > p[j].val) {
    24                 node top = sta.top(); sta.pop();
    25                 if(!sta.empty()) sta.top().suf += top.suf;
    26                 p[j].pre += top.pre;
    27                 square = max(square, (top.suf + top.pre - 1) * top.val);
    28             }
    29             sta.push(p[j]);
    30         }
    31         while(!sta.empty()) {
    32             node top = sta.top(); sta.pop();
    33             if(!sta.empty()) sta.top().suf += top.suf;
    34             square = max(square, (top.suf + top.pre - 1) * top.val);
    35         }
    36     }
    37     if(square >= k) return true;
    38     return false;
    39 }
    40 
    41 void solve() {
    42     int t;
    43     scanf("%d", &t);
    44     while(t--) {
    45         scanf("%d%d%d", &n, &m, &k);
    46         int r = 0, l = 1000000000, ans;
    47         for(int i = 1; i <= n; i++) {
    48             for(int j = 1; j <= m; j++) {
    49                 scanf("%lld", &mat[i][j]);
    50                 if(mat[i][j] < l) l = mat[i][j];
    51                 if(mat[i][j] > r) r = mat[i][j];
    52             }
    53         }
    54         ans = l;
    55         while(l <= r) {
    56             int mid = (l + r) >> 1;
    57             if(check(mid)) l = mid + 1, ans = mid;
    58             else r = mid - 1;
    59         }
    60         check(ans);
    61         printf("%d %d
    ", ans, square);
    62     }
    63 }
    64 
    65 int main() {
    66     solve();
    67     return 0;
    68 }
  • 相关阅读:
    Windows下Rails2.0.2最简安装教程
    xmpp with openfire之三 openfire扩展小试 整合现有系统用户
    母亲的电话
    郁闷……
    博弈
    长春下雪了
    监考
    sql把逗号分隔的字符串拆成临时表
    SQL语句使用大全。
    Left Join、Right Join、Inner Join的区别
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6502026.html
Copyright © 2011-2022 走看看