声明
此题解并不是Sgu250原题,输出与原题不同
Description
艺术节就要开始了,但是 Jolin是一个很臭屁的人,她要求把舞台设置成 C字形
的。艺术节的会场是一个 n*m的矩阵,有的地方安排了座位,被标记为 1;还有
些地方是空地,被标记为 0。只有在空地才能搭建舞台。
C字形的舞台是这样的舞台:
1.它由从上到下排开的矩形组成
2.三个矩形的左边界相同
3.第一个矩形的下边界和第二个矩形的上边界,第二个矩形的下边界和第三个
矩形的上边界相邻。
4.第二个矩形的右边界必须小于第一个和第二个矩形的右边界。
作为疯狂迷恋 Jolin的Fans,你希望让舞台尽量的大。
Input
输入数据第一行是两个数 n, m(1<=n,m<=200)。
接下来是一个 n*m的矩阵,是 0或者 1。意义如上所述
Output
输出舞台最大面积。
Sample Input
input 1 8 7 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 input 2 8 8 1 1 1 1 1 1 1 1 1 0 0 0 0 1 0 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 0 1 0 1 0 0 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
Sample Output
output1 19 output 2 12
分析
题意比较清晰
首先,我们进行一波预处理
g[ i ][ k ]表示以第i行为上边界,以第k行为下边界的矩形向右延伸的最大宽度
n1[ i ][ k ]表示以第i行为上边界,下边界∈[ i, k ]的矩形中最大的矩形的下边界行数
n2[ i ][ k ]表示以第k行为下边界,上边界∈[ 1, i ]的矩形中最大的矩形的上边界行数
大致流程
枚举中间矩形的上边界i
枚举下边界k,那么中间矩形的宽度就是g[ i ][ k ]
分别二分答案向上和向下的最大矩形的宽度,若宽度小于中间矩形宽度则进入下一重循环
更新答案
若中间矩形的宽度等于上面或者下面的矩形宽度
若中间矩形宽度<=1或者当前情况下的三个矩形面积之和只比ans大1,进入下一重循环
(因为我们要把中间矩形的宽度减一)
否则直接更新最大值
结束
代码
#include<bits/stdc++.h>
using namespace std;
int n, m;
int p[210][210], g[210][210];
int n1[210][210], n2[210][210];
int ans;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
return x * f;
}
int main() {
n = read(), m = read();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
p[i][j] = read();
}
}
for(int j = m; j >= 1; j--) {
for(int i = 1; i <= n; i++) {
int k = i;
while (k <= n && !p[k][j]) g[i][k++]++;
while (k <= n) g[i][k++] = 0;
}
for(int i = 1; i <= n; i++) {
n1[i][i] = i;
for(int k = i + 1; k <= n; k++) {
if(g[i][n1[i][k - 1]] * (n1[i][k - 1] - i + 1) < g[i][k] * (k - i + 1)) n1[i][k] = k;
else n1[i][k] = n1[i][k-1];
}
}
for(int k = n; k >= 1; k--) {
n2[k][k] = k;
for(int i = k - 1; i >= 1; i--) {
if(g[n2[i + 1][k]][k] * (k - n2[i + 1][k] + 1) < g[i][k] * (k - i + 1)) n2[i][k] = i;
else n2[i][k] = n2[i + 1][k];
}
}
for(int i = 1; i <= n; i++) if(g[i][i]) {
for(int k = i + 2; k <= n && g[k][k]; k++) {
int a, b, c, all, low, high, mid, U, D;
b = g[i + 1][k - 1];
if(b <= 0) break;
b = min(b, min(g[i][i], g[k][k]));
low = 1;
high = i;
while(low <= high) {
mid = (low + high) >> 1;
if(g[n2[mid][i]][i] >= b) high = mid - 1, a = mid;
else low = mid + 1;
}
if(g[n2[a][i]][i] < b) continue;
low = k;
high = n;
while(low <= high) {
mid = (low + high) >> 1;
if(g[k][n1[k][mid]] >= b) low = mid + 1, c = mid;
else high = mid - 1;
}
if(g[k][n1[k][c]] < b) continue;
U = n2[a][i], D = n1[k][c];
a = g[U][i], c = g[k][D];
all = a * (i - U + 1) + b * (k - i - 1) + c * (D - k + 1);
if(b == a || b == c) {
if(b <= 1 || --all <= ans) continue;
ans = all;
} else if(all > ans) ans = all;
}
}
}
printf("%d", ans);
}