2019南昌邀请赛网络预选赛 I. Max answer(单调栈+暴力??)

传送门

 

题意:

  给你你一序列 a,共 n 个元素,求最大的F(l,r);

  F(l,r) = (a[l]+a[l+1]+.....+a[r])*min(l,r);

  ([l,r]的区间和*区间最小值,F(l,r)是我单独定义的,为了方便理解);

我的思路:

  分两部分来(看这篇文章的童鞋请先戳这篇文章👉):

  1.区间最小值为非负数,此区间一定不包含负数,直接用单调栈求出以某个非负数a[i]为最小值的左右区间L[i],R[i];

   然后答案取 ∀i ∈[1,n],a[i] ≥ 0, max{ a[i]*区间和};

  2.区间最小值为负数,此时,此区间可能包含负数,还是先用单调栈求出以某个负数a[i]为最小值的左右区间L[i],R[i];

   定义 minL[ i ] 为区间 j ∈[ L[i] , i ] 的最小的 a[ j ]+a[ j+1 ]+.....+a[ i ];

     然后,预处理出 ∀i ∈[1,n],a[i] < 0, 的minL[ i ];

   对于∀i ∈[1,n],a[i] < 0, j 每次从 i+1 到 R[i] 遍历一遍,答案取 max{ a[i]*(minL[i]+a[ j ]) }

  最后,答案取这两种情况的最大值;

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define ll long long
 6 #define mem(a,b) memset(a,b,sizeof(a))
 7 const int maxn=5e5+50;
 8 
 9 int n;
10 int a[maxn];
11 int L[maxn];
12 int R[maxn];
13 int sta[maxn];
14 ll sum[maxn];
15 ll minL[maxn];
16 
17 void F()//单调栈,求出L[],R[];
18 {
19     int index=0;
20     for(int i=1;i <= n;++i)
21     {
22         while(index > 0 && a[i] <= a[sta[index]])
23             index--;
24         if(index == 0)
25             L[i]=1;
26         else
27             L[i]=sta[index]+1;
28         sta[++index]=i;
29     }
30     index=0;
31     for(int i=n;i >= 1;--i)
32     {
33         while(index > 0 && a[i] <= a[sta[index]])
34             index--;
35         if(index == 0)
36             R[i]=n;
37         else
38             R[i]=sta[index]-1;
39         sta[++index]=i;
40     }
41 }
42 ll Solve()
43 {
44     F();
45     mem(minL,0);
46     for(int i=1;i <= n;++i)
47     {
48         if(a[i] >= 0)
49             continue;
50         for(int j=L[i];j <= i;++j)
51             minL[i]=min(minL[i],sum[i]-sum[j-1]);//预处理出负数a[i]的minL[i]
52     }
53     ll ans=0;
54     //两部分取最大值
55     for(int i=1;i <= n;++i)
56     {
57         if(a[i] >= 0)
58         {
59             ans=max(ans,a[i]*(sum[R[i]]-sum[L[i]-1]));
60             continue;
61         }
62         ans=max(ans,a[i]*minL[i]);
63         for(int j=i+1;j <= R[i];++j)
64             ans=max(ans,a[i]*(minL[i]+sum[j]-sum[i]));
65     }
66     return ans;
67 }
68 int main()
69 {
70     while(~scanf("%d",&n))
71     {
72         sum[0]=0;
73         for(int i=1;i <= n;++i)
74         {
75             scanf("%d",a+i);
76             sum[i]=sum[i-1]+a[i];
77         }
78         printf("%lld\n",Solve());
79     }
80     return 0;
81 }
View Code
posted @ 2019-04-21 20:06  HHHyacinth  阅读(276)  评论(0编辑  收藏  举报