这一次可怜的题目是lightoj 1083 Histogram.
题意
很简单,就是求最大子矩形的面积大小。
思路
可以用暴枚,复杂度 O(n2) O ( n 2 ) ,在30000的复杂度下会炸。以下是传说中的 4 4 种方法。
单调栈法
可以知道对于任何一条矩形来讲,决定以它高度为宽的最大矩形只能从在它左边第一个比它小的矩形的后面一个到在它右边第一个比它小的矩形的前面一个为止。
这样利用栈就可以达成O(n)的复杂度了。
要注意的是,在结束时,必须放进去一个0把栈清空,否则一旦所有矩形呈升序排列你就没有答案了。
#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int boss=1e5,inf=0x3f3f3f3f;
int a[boss+10],answer=-inf,n;
stack<pii> s;
void get_max()
{
int i;
s.push((pii){-1,0});
for (i=1;i<=n+1;i++)//注意这里是n+1,还要再进去一个0。
{
pii p=s.top();
while (a[p.second]>a[i]&&!s.empty())//遇到比这个矩形要高的不断弹出之
{
answer=max(answer,abs(i-p.first-1)*a[p.second]);//更新最大值
s.pop();
if (!s.empty()) p=s.top();
}
s.push((pii){p.second,i});
}
}
int read()
{
int x=0;char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
int main()
{
for (int t=read(),cases=0,i;t--;a[n+1]=0,get_max(),printf("Case %d: %d\n",++cases,answer),answer=-inf)//初始化
{
n=read();
for (i=1;i<=n;i++) a[i]=read();
}
}
kmp?并查集法。
利用一个类似于的递推式找出在该矩形左右第一个比它低的矩形的位置。
代码比上一个方法”好懂”。
#include<bits/stdc++.h>
using namespace std;
int a[30010],l[30010],r[30010],n,cases;
int read()
{
int x=0;char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
int main()
{
int t=read();
while (t--)
{
int i;
for (n=read(),i=1;i<=n;i++) a[i]=read();
for (i=1;i<=n;i++)
{
l[i]=i;
while (l[i]>1&&a[l[i]-1]>=a[i]) l[i]=l[l[i]-1];//这里和下面两句话是精髓
}
for (i=n;i>=1;i--)
{
r[i]=i;
while (r[i]<n&&a[r[i]+1]>=a[i]) r[i]=r[r[i]+1];
}
int da=-0x3f3f3f3f;
for (i=1;i<=n;i++) da=max(da,(r[i]-l[i]+1)*a[i]);
printf("Case %d: %d\n",++cases,da);
}
}
笛卡尔树法
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
int x=0,f=1;char c=gc();
for (;!isdigit(c);c=gc()) f^=c=='-';
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return f?x:-x;
}
template <typename mitsuha>
inline bool read(mitsuha &x){
x=0;int f=1;char c=gc();
for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
if (!~c) return 0;
for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
return x=f?x:-x,1;
}
template <typename mitsuha>
inline int write(mitsuha x){
if (!x) return 0&pc(48);
if (x<0) x=-x,pc('-');
int bit[20],i,p=0;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i;--i) pc(bit[i]+48);
return 0;
}
inline char fuhao(){
char c=gc();
for (;isspace(c);c=gc());
return c;
}
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
ll llx;int n=read();
struct _tree{
struct node{
int fa,ls,rs,key,id;
}r[yuzu|10];
void build(int n){
r[0].key=0,r[0].rs=1;
r[1].key=read(),r[1].id=1;
for (int i=2,p;i<=n;++i){
r[i].key=read(),r[i].id=i;
for (p=i-1;r[i].key<r[p].key;p=r[p].fa);
r[i].ls=r[p].rs,r[p].rs=i,r[i].fa=p;
}
}
void dfs(int u,int z=1,int y=n){
if (z>y) return;
llx=max(llx,1ll*(y-z+1)*r[u].key);
dfs(r[u].ls,z,r[u].id-1);
dfs(r[u].rs,r[u].id+1,y);
}
}my_;
int main(){
my_.build(n);
my_.dfs(my_.r[0].rs),write(llx);
}