P2659 美丽的序列

Posted HWIM

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2659 美丽的序列相关的知识,希望对你有一定的参考价值。

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。 提示 你可能需要一个读入优化。

 

做法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 } 

 

以上是关于P2659 美丽的序列的主要内容,如果未能解决你的问题,请参考以下文章

P2659 美丽的序列

单调栈模板题 luogu P2659

[SOJ475]SPC #2美丽的序列 ~ Beautiful Sequence莫队哈希

和 Thrift 的一场美丽邂逅

转载和 Thrift 的一场美丽邂逅

bzoj3809:Gty的二逼妹子序列