給定一段序列, 其中元素 \(0 \leq a_{i} \leq 100000\)
定義一段子段 \([L, R]\) 的溫馨值爲 \(\min_{L \leq i \leq R}a_{i} * \sum_{i = L}^{R}a_{i}\)
求最大溫馨值(並定位其位置)
\(n \leq 500000\)ios
首先 \(O(n^{2})\) 枚舉區間, 前綴和亂搞啥的顯然不合理
考慮式子, 後一項咱們能夠前綴和求出, 因而重點放在 \(\min_{L \leq i \leq R}a_{i}\) 上
對於一個 \(a_{i}\), 貪心可知覆蓋越廣溫馨值越大
枚舉每個 \(a_{i}\) 做爲區間最小值, 而後能夠單調棧 \(O(1)\) 求出每一個 \(d_{i}\) 對應的最長左區間
同理能夠 \(O(n)\) 求出對應右端點
總複雜度 \(O(n)\)spa
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<algorithm> #include<climits> #define LL long long #define REP(i, x, y) for(LL i = (x);i <= (y);i++) using namespace std; LL RD(){ LL out = 0,flag = 1;char c = getchar(); while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();} while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();} return flag * out; } const LL maxn = 200019, INF = 0xfffffffffffffff; LL num; LL a[maxn], sum[maxn]; LL l[maxn], r[maxn]; struct Stack{ LL Index, val; }S[maxn]; LL top; void get_l(){ top = 0; S[++top].Index = 0; S[top].val = -INF; REP(i, 1, num){ while(top >= 1 && S[top].val >= a[i])top--; l[i] = S[top].Index + 1; S[++top].Index = i; S[top].val = a[i]; } } void get_r(){ top = 0; S[++top].Index = num + 1; S[top].val = -INF; for(LL i = num;i >= 1;i--){ while(top >= 1 && S[top].val >= a[i])top--; r[i] = S[top].Index - 1; S[++top].Index = i; S[top].val = a[i]; } } int main(){ while(scanf("%lld", &num) != EOF){ memset(sum, 0, sizeof(sum)); memset(a, 0, sizeof(a)); memset(l, 0, sizeof(l)); memset(r, 0, sizeof(r)); REP(i, 1, num)a[i] = RD(), sum[i] = sum[i - 1] + a[i]; get_l(); get_r(); LL ans = 0, L = 0, R = 0; REP(i, 1, num){ if((sum[r[i]] - sum[l[i] - 1]) * a[i] >= ans){ ans = (sum[r[i]] - sum[l[i] - 1]) * a[i]; L = l[i], R = r[i]; } } printf("%lld\n%lld %lld\n\n", ans, L, R); } return 0; }