题目背景
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。 提示 你可能需要一个读入优化。
做法1
分析
我的天啊,第二个测试点964ms卡过。。。(再交一次就不一定过了。。。90)
然后写一下思路吧:
用线段树logn找出最小值,以及最小值的位置,
包含最小值的所有区间的最大值,应该是区间长度最长的。
当前区间[l,r],最小值mn,它的位置pos,
包含最小值:[l,r]的答案就是mn*(r-l+1)
不包含最小值:将[l,r]分成两段,[l,pos-1],[pos+1,r]在这两个区间递归,像上面这样做。详见代码
(笛卡尔树)
code
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 #define lson l,m,rt<<1 5 #define rson m+1,r,rt<<1|1 6 #define INF 0x7fffffff 7 #define MAXN 2000100 8 #define LL long long 9 struct MN { 10 int mn,pos; 11 }t[MAXN<<2]; 12 LL ans = 0; 13 int n; 14 inline int read() { 15 int x = 0,f = 1;char ch = getchar(); 16 for (; ch<'0'||ch>'9'; ch = getchar()) 17 if (ch=='-') f = -1; 18 for (; ch>='0'&&ch<='9'; ch = getchar()) 19 x = x*10+ch-'0'; 20 return x*f; 21 } 22 inline void pushup(int rt) { 23 if (t[rt<<1].mn < t[rt<<1|1].mn) t[rt].mn = t[rt<<1].mn, t[rt].pos = t[rt<<1].pos; 24 else t[rt].mn = t[rt<<1|1].mn, t[rt].pos = t[rt<<1|1].pos; 25 } 26 void build(int l,int r,int rt) { 27 if (l==r) { 28 t[rt].mn = read(); 29 t[rt].pos = l; 30 return; 31 } 32 int m = (l+r)>>1; 33 build(lson); 34 build(rson); 35 pushup(rt); 36 } 37 MN query(int l,int r,int rt,int L,int R) { 38 if (L<=l && r<=R) { 39 return t[rt]; 40 } 41 int m = (l+r)>>1; 42 MN t,ret; 43 ret.mn = INF; 44 if (L<=m) ret = query(lson,L,R); 45 if (R>m) { 46 t = query(rson,L,R); 47 if (t.mn < ret.mn) ret = t; 48 } 49 return ret; 50 } 51 void solve(int l,int r) { 52 MN m = query(1,n,1,l,r); 53 ans = max(ans,1ll*(r-l+1)*m.mn); 54 if (l<m.pos) solve(l,m.pos-1); 55 if (m.pos<r) solve(m.pos+1,r); 56 } 57 int main() { 58 n = read(); 59 build(1,n,1); 60 solve(1,n); 61 printf("%lld",ans); 62 return 0; 63 }
做法2
分析
分别求出每个元素向左和向右扩展的最大长度
最后每个元素获得的最大值等于(向左延伸的长度 + 向右延伸的长度 + 1)* 元素的值
使用单调栈可以O(n)算出。
code
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 #define INF 0x7fffffff 7 #define MAXN 2000100 8 #define LL long long 9 10 int st[MAXN],pos[MAXN],a[MAXN],top,R[MAXN]; 11 12 inline int read() { 13 int x = 0,f = 1;char ch = getchar(); 14 for (; ch<'0'||ch>'9'; ch = getchar()) 15 if (ch=='-') f = -1; 16 for (; ch>='0'&&ch<='9'; ch = getchar()) 17 x = x*10+ch-'0'; 18 return x*f; 19 } 20 21 int main() { 22 23 int n = read(); 24 LL ans = 0,sum; 25 for (int i=1; i<=n; ++i) a[i] = read(); 26 27 a[0] = a[n+1] = -1; 28 st[(top=0)] = 0; 29 for (int i=1; i<=n+1; ++i) { 30 while (a[st[top]] > a[i]) { 31 R[st[top]] = i-1; 32 top--; 33 } 34 st[++top] = i; 35 } 36 37 st[(top=0)] = 0; 38 for (int i=n; i>=0; --i) { 39 while (a[st[top]] > a[i]) { 40 sum = 1ll*(R[st[top]]-i)*a[st[top]];//right R[],left i+1 R-(i+1)+1->R-i 41 ans = max(ans,1ll*(R[st[top]]-i)*a[st[top]]); 42 top--; 43 } 44 st[++top] = i; 45 } 46 47 printf("%lld",ans); 48 49 return 0; 50 }