P2659 美麗的序列
阿新 • • 發佈:2017-10-15
分析 所有 美好 -- 美麗 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> 3using 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 美麗的序列