1. 程式人生 > >P2659 美麗的序列

P2659 美麗的序列

分析 所有 美好 -- 美麗 push hold ++ 笛卡爾

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 美麗的序列