目录
目录
最大矩形面积
题目
此题很容易想到的一个方法莫过于暴搜了,
代码
#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<iostream>
using namespace std;
inline void read(LL &x){
LL f = 1;
x = 0;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int n;
LL a[L],max_x;
inline LL max(LL x,LL y){
return x > y ? x : y;
}
int main(){
scanf("%d",&n);
for (register int i = 1;i <= n; ++ i)
read(a[i]);
for (register int i = 1;i <= n; ++ i){
int j = i - 1;
while (a[j] >= a[i])
-- j;
++ j;
int k = i + 1;
while (a[k] >= a[i])
++ k;
max_x = max(max_x,a[i] * (k - j));
}
printf("%lld\n",max_x);
return 0;
}
很真实,再看看时间:
对比一下正解就知道它的吓人之处了
所以做题时,不一定要按要求正解呢,不说多了,看看正解吧
正解
首先做题得有份草图
然后你得明白他是单调队列,接着你得知道矩形的特征
(1)矩形具有平行四边形的所有性质:对边平行且相等,对角相等,邻角互补,对角线互相平分;
(2)矩形的四个角都是直角;
由此可以想到此题,设 i 柱体的标号,a[ i ]为当前柱体的高,则此时矩形的宽就是向两边一直延伸到某一个高度小于他的柱体(一个柱体的宽为1)
(暴搜代码的思路,理解了接下来就很好办了)
我们定义一个栈,保持它单调上升(及1,2,3,5,8,100),假设此时有一个高度为 hight 的柱体,现在要求以他的高为高的矩形,因为要保持单调上升,由脑补得,比他高的柱体都被他出了栈,留下的都只有比他矮的,而对于这些被踢出栈的元素来说,这是第一个比他矮的柱体,则对于这些柱体来说,他们宽的右端点可以一直延续到 i - 1 ;
现在差的还有左端点,我们先倒数3秒,把自己从被踢出的元素中,转换到踢他的元素中(a[ i ])
再来回顾一下单调队列,单调上升,踢出的元素都是比要添加元素高度高的。
所以对于 i 号元素来讲,他的左端点就是他踢出元素的左端点
这就相当于有三个数a,b,c
- a > b
- b > c
- a > c
不说多了,看代码
代码(2)
#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<stack>
#include<iostream>
using namespace std;
inline void read(LL &x){
LL f = 1;
x = 0;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
struct node{
LL x,y;
}a[L];
LL n,max_x;
stack < node > Q;
int main(){
read(n);
for (int i = 1; i <= n; ++ i){
read(a[i].x);
a[i].y = 1;
}
Q.push(a[1]);
for (int i = 2;i <= n + 1; ++ i){
int f = 0;
while (a[i].x < Q.top().x){//假如这个新柱,比前面的高度小,则这个矩形的高度就不可能越过当前高度
if (Q.size() - 1 == 0){
node t1 = Q.top();
max_x = max(max_x,t1.x * t1.y);
t1.y += a[i].y;
Q.pop();
t1.x = a[i].x;
Q.push(t1);
f = 1;
break;
}
node t1 = Q.top();
Q.pop();
max_x = max(max_x,t1.x * t1.y);
node t2 = Q.top();
Q.pop();
t2.y += t1.y;
Q.push(t2);
}
if ( ! f)
Q.push(a[i]);
}
printf("%lld\n",max_x);
return 0;
}
或者说
#include<cstdio>
#define L 100000 + 5
#define LL long long
#include<stack>
using namespace std;
inline void read(LL &x){
LL f = 1;
x = 0;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
x *= f;
}
int n;
LL a[L],max_x;
struct node{
int pos;
LL hi;
};
inline LL max(LL x,LL y){
return x > y ? x : y;
}
int main(){
scanf("%d",&n);
for (register int i = 1;i <= n; ++ i)
read(a[i]);
stack < node > Q;
for (register int i = 1;i <= n + 1; ++ i){
node t1;
t1.hi = a[i];
t1.pos = i;
if (Q.empty()){
Q.push(t1);
} else {
if (Q.top().hi < t1.hi){
Q.push(t1);
} else{
if (Q.top().hi > t1.hi){
int ip = i;
while ( ! Q.empty() && Q.top().hi >= t1.hi){
node t2 = Q.top();
Q.pop();
max_x = max(max_x,t2.hi * (i - t2.pos));
ip = t2.pos;
}
t1.pos = ip;
Q.push(t1);
}
}
}
}
printf("%lld\n",max_x);
return 0;
}
于此代码而言……
附(矩形牛棚)
然后用这个思路就可以做出矩形牛棚了
同样的代码,你只需一行一行的处理即可,及对于每一行的第 i 个元素,他就一定等于上一行的第 i 号元素 + 1即可(当然,被破坏的草坪高度为0),这样处理完后,就可以通过调用最大矩形面积的代码就可以AC了
代码(3)
#include<cstdio>
#include<stack>
#define L 3000 + 5
using namespace std;
inline void read(int &x){
x = 0;
int f = 1;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s -'0';
s = getchar();
}
x *= f;
}
int n,m,t,max_x;
struct node{
int hi,pos;
};
int a[L][L];
void s_q(int step){
stack < node > Q;
for (register int i = 1;i <= m + 1; ++ i){
node t1;
t1.hi = a[step][i];
t1.pos = i;
if (Q.empty()){
Q.push(t1);
} else {
if (Q.top().hi < t1.hi){
Q.push(t1);
} else{
if (Q.top().hi > t1.hi){
int ip = i;
while ( ! Q.empty() && Q.top().hi >= t1.hi){
node t2 = Q.top();
Q.pop();
max_x = max(max_x,t2.hi * (i - t2.pos));
ip = t2.pos;
}
t1.pos = ip;
Q.push(t1);
}
}
}
}
}
inline int max(int x,int y){
return x < y ? y : x;
}
int main()
{
read(n);
read(m);
read(t);
for (register int i = 1;i <= t; ++ i){
int x,y;
read(x);
read(y);
a[x][y] = -1;
}
for (register int i = 1;i <= n; ++ i)
for (register int j = 1;j <= m; ++ j)
if (a[i][j] != -1) a[i][j] = a[i - 1][j] + 1;
else a[i][j] = 0;
for (register int i = 1;i <= n; ++ i)
s_q(i);
printf("%d\n",max_x);
return 0;
}