P2659 美丽的序列
题目背景
GD是一个热衷于寻求美好事物的人,一天他拿到了一个美丽的序列。
题目描述
为了研究这个序列的美丽程度,GD定义了一个序列的“美丽度”和“美丽系数”:对于这个序列的任意一个区间[l,r],这个区间的“美丽度”就是这个区间的长度与这个区间的最小值的乘积,而整个序列的“美丽系数”就是它的所有区间的“美丽度”的最大值。现在GD想要你帮忙计算这个序列的“美丽系数”。
输入输出格式
输入格式:
第一行一个整数n,代表序列中的元素个数。 第二行n个整数a1、a2„an,描述这个序列。
输出格式:
一行一个整数,代表这个序列的“美丽系数”。
输入输出样例
输入样例#1: 复制
3
1 2 3
输出样例#1: 复制
4
说明
样例解释 选取区间[2,3],可以获得最大“美丽系数”为2*2=4。 数据范围 对于20%的数据,n<=2000; 对于60%的数据,n<=200000; 对于100%的数据,1<=n<=2000000,0<=ai<=2000000。 提示 你可能需要一个读入优化。
这个题目很熟悉
以前接触过
首先这是一个分治算法
找出整段序列的最小值
然后递归最小值两侧求解
这个做法可以用线段树等结构维护
然后还有一个比较简单的单调栈做法
#include<iostream>
#include<cstdio>
#define N 20000005
using namespace std;
int anss;
struct node{
int l,r,s,pos;
};
struct segment{
int n;
node t[N];
void PushUp(int ret){
if(t[t[ret<<1].pos].s>t[t[ret<<1|1].pos].s)
t[ret].pos=t[t[ret<<1].pos].s;
else t[ret].pos=t[t[ret<<1|1].pos].s;
}
inline void Build(int l,int r,int ret){
t[ret].l=l;t[ret].r=r;
if(l==r){
t[ret].pos=ret;
anss=max(anss,t[ret].s);
scanf("%d",&t[ret].s);
return;
}
int mid=(l+r)>>1;
Build(l,mid,ret<<1);
Build(mid+1,r,ret<<1|1);
PushUp(ret);
}
int Gmin(int a,int b){
return t[a].s>t[a].s?a:b;
}
inline int query(int ret,int L,int R){
int l=t[ret].l,r=t[ret].r;
if(l>=L&&r<=R)
return t[ret].pos;
int mid=(l+r)>>1;
int ans=0x7fffffff;
if(R>mid)ans=Gmin(ans,query(ret<<1|1,L,R));
if(L<=mid)ans=Gmin(ans,query(ret<<1,L,R));
return ans;
}
}Now;
int ans(int l,int r){
if(l==r)return 0;
int pos=Now.query(1,l,r);
int minl=Now.t[pos].l;
int ansl=0;
ansl=max((r-l+1)*Now.t[pos].s,max(ans(l,minl-1),ans(minl+1,r)));
return ansl;
}
int main(){
int n,m;
cin>>n>>m;
Now.Build(1,n,1);
printf("%d",ans(1,n));
return 0;
}