499. 牛宫
★★ 输入文件:long.in
输出文件:
long.out
简单对比
时间限制:1 s 内存限制:128 MB
Description
AP神牛准备给自己盖一座很华丽的宫殿。于是,他看中了一块N*M的矩形空地。空地中每个格子都有自己的海拔高度。AP想让他的宫殿的平均海拔在海平面之上(假设海平面的高度是0,平均数都会算吧?)。而且,AP希望他的宫殿尽量大,能够容纳更多的人来膜拜他。请问AP的宫殿最后会有多大?
Input Format
第一行为N和M。之后N行,每行M个数,描述的空地的海拔。
Output Format
输出一行,表示宫殿最大面积。
Sample Input
3 2
4 0
-10 8
-2 -2
Sample Output
4
Data Limit
对于30%的数据,N,M≤50;
对于100%的数据,N,M≤200;
暴力枚举肯定会超时的, 四重循环啊,可以得50分, 然后就是TTTTT;
受到hzwer博客的启发:
可以先暴力枚举矩形的两个端点 L和R, 然后在行里找最值, 其实这个极妙的思路我表达不清楚, 一切尽在代码中;
最重要的是这么一个结论:令si表示前i行, L到R的海拔高度之和,
如果si前面有个sj 且sj<si 那么从j+1到i 宽为R-L+1 一段区间海拔和(si-sj)>0, 这样就找到一个满足题目要求的区间;
更新答案即可;
怎么找sj呢, 把s和他所对应的编号i捆绑, 按照s从小到大排序;
遍历一遍, 遍历过程中维护一个值, 就是最小编号MIN,
ans=max(ans, (s[i].id-MIN)*(y-x+1)); 这样就可以更新答案了;
这个结论是非常妙的, 不理解的话, 自己模拟一下就会懂了;
悄悄地奉上代码;
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=200+10;
const int INF=0x3f3f3f3f;
struct NB {
LL num;
int id;
bool operator < (const NB& n) const {
return num<n.num;
}
} s[maxn];
LL a[maxn][maxn];
int n, m, ans, cnt;
int main()
{
freopen("long.in", "r", stdin);
freopen("long.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
scanf("%lld", &a[i][j]);
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
for(int x=1; x<=m; x++) {
for(int y=x; y<=m; y++) {
cnt=-1;
s[++cnt]=((NB){0, 0});
for(int i=1; i<=n; i++) {
LL S=a[i][y]-a[i][x-1];
s[++cnt]=((NB){S, i});
}
sort(s, s+cnt+1);
int MIN=INF;
for(int i=0; i<=cnt; i++) {
MIN=min(MIN, s[i].id);
ans=max(ans, (s[i].id-MIN)*(y-x+1));
}
}
}
printf("%d", ans);
return 0;
}
如想看单调栈的代码: 黄学长博客 点击打开链接