广告印刷 单调栈
通过单调栈的每一次出栈来更新最大值入栈的时候前面的高楼对当前矮楼只有累加宽度而且在前面的高楼出栈的时候就已经在更新最大值所以才可以把高楼的宽度累加到矮楼上因为他们的其他情况已经被考虑多出来的那块已经没用了完全可以被合并成一个大楼。
#include <iostream>
#include <cmath>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
//int maxx,minn,j,k,a[100000];
int n,x[100009],ans=0,a[100009],y[100009];
long long maxx=-1;
long long max(long long a,long long b)
{
return a>b?a:b;
}
int main()
{
std::ios::sync_with_stdio(false);
while(scanf("%d",&n),n!=0)
{
maxx=-1;
memset(x,0,sizeof(x));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
a[0]=a[n+1]=-1;
for(int i=1;i<=n+1;i++)
{
if(a[i]>x[ans])
{
x[++ans]=a[i];
y[ans]=1;
}
else
{
int weigh=0;
while(x[ans]>=a[i]&&ans>0)
{
weigh+=y[ans];
maxx=max(maxx,(long long)weigh*x[ans]);
ans--;
}
x[++ans]=a[i];
y[ans]=1+weigh;
}
}
printf("%lld\n",maxx);
}
}
第二种方法通过两次遍历找到每个点的向左能扩展到那个位置向右能扩展到那个位置或者记录向左能走多长向右能走多长(一样的无非就是left数组right数组的记录方式和最后max的判断方式有所细微的差别)。(在此我记录的是向左右扩展的位置)关键是我用这种方法在做的时候没有想到对 表示“栈”的这个数组进行初始化然后一直WA。
#include <iostream>
#include <cmath>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
//int maxx,minn,j,k,a[100000];
int n,x[100009],ans=0,a[100009],y[100009],l[100090],r[100090];
long long max(long long a,long long b)
{
return a>b?a:b;
}
long long int maxx=-1;
int main()
{
while(~scanf("%d",&n),n!=0)
{
ans=0;
memset(x,0,sizeof(x));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
x[0]=0;//标记标记标记!!!!
for(int i=1;i<=n;i++)
{
while(a[x[ans]]>=a[i]&&ans>0)
{
ans--;
}
l[i]=x[ans];
x[++ans]=i;
}
ans=0;
memset(x,0,sizeof(x));
x[0]=n+1;//标记标记标记!!!
for(int i=n;i>=1;i--)
{
while(a[x[ans]]>=a[i]&&ans>0)
{
ans--;
}
r[i]=x[ans];
x[++ans]=i;
}
maxx=-1;
for(int i=1;i<=n;i++)
{
maxx=max(maxx,(long long)(r[i]-l[i]-1)*a[i]);
}
printf("%lld\n",maxx);
}
}