小记:1A! 看到这个求最大矩阵的面积,我就想起了前面的1506,1505,2870了, 感觉方法应该不会差太大, 于是从这个方面入手,最后加了树状数组解决的
思路:此题和1505的差别就在于可以任意交换两列,那么我们就可以看成,当处理某一行,我们处理某一点时,
我们保存这点左边的大于它的高度的个数, 以及右边大于它的高度的个数,个数即列数
我们知道这两个值时,那么从上往下处理行时,我们就可以一点一点的求得其通过交换之后,即将那些大于它的高度的列全部移到一起。所能得到的最大面积,就知道了
然后保存最大的那个值就是answer了
求左边大于它的高度和右边大于它的高度的个数,很容易好想到可以用树状数组解决。
于是加个树状数组来求取左右值。时间复杂度为O(n*m*logm), 3s内完全没问题
code:
#include <iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> using namespace std; #define mst(a,b) memset(a,b,sizeof(a)) #define REP(a,b,c) for(int a = b; a < c; ++a) #define eps 10e-8 const int MAX_ = 1010; const int N = 1010; const int INF = 0x7fffffff; int h[MAX_]; int l[MAX_], r[MAX_]; char str[MAX_][MAX_]; int C[MAX_]; int lowbit(int x){return x&(-x);} void add(int x,int num){ while(x < N){ C[x] += num; x += lowbit(x); } } int sum(int x){ int cnt = 0; while(x){ cnt += C[x]; x -= lowbit(x); } return cnt; } int main(){ int n, m, ans; while(~scanf("%d%d", &n, &m)){ REP(i, 0, m){ h[i] = 0; } ans = -1; REP(j, 0, n){ scanf("%s", str[j]); REP(i, 0, m){ switch(str[j][i]){ case '1': h[i] ++; break; case '0': h[i] = 0; break; } } mst(C, 0); REP(i, 0, m){ add(h[i]+1, 1); l[i] = i - sum(h[i]) + 1; //printf("%d ", l[i]); } //printf("\n"); mst(C, 0); for(int i = m-1; i > -1; --i){ add(h[i]+1, 1); r[i] = m - i - sum(h[i] + 1); //printf("%d ", r[i]); } //printf("\n"); REP(i, 0, m){ int tmp = h[i] * (r[i] + l[i]); ans = max(ans, tmp); } } printf("%d\n", ans); } return 0; }