论如何用四种方法扫荡一道题

这一次可怜的题目是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?并查集法。

利用一个类似于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);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值