1 solutions
-
0
/* 本题的知识点就是前缀和+单调队列。
其中我们要找的就是连续子区间的最大值和连续子区间的最小值。所以我们需要维护两个单调队列,一个维护前缀和的最小值,一个维护前缀和的最大值。
当维护前缀和的最小值的时候,当前位置的前缀和-前面最小的前缀和就是到当前位置最大的子区间和。
代码如下: ———————————————— 版权声明:本文为CSDN博主「weixin_66009678」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_66009678/article/details/136812639
*/
#include <bits/stdc++.h> using namespace std; #define print(x) std::cout<<#x<<'='<<(x)<<endl; const int N=3e5+5; typedef long long ll; ll ans; int a[N]; int n,c; ll s[N];//前缀和 ll solve1()//求连续子区间的最大值,然后*C,再返回总和 { deque<int> q;//存前缀和的最小值 q.push_back(0); ll sum=0; int l,r;//最大值对应的连续子区间的左右端点 l=0; r=0; for(int i=1;i<=n;i++) { while(q.empty()==0&&s[i]<=s[q.back()]) { q.pop_back(); } if(q.empty()==0) { if(sum<(s[i]-s[q.front()])) { sum=s[i]-s[q.front()]; l=q.front(); r=i; } } q.push_back(i); } ll res=0; res=s[l]+s[n]-s[r]+sum*c; return res>s[n]?res:s[n]; } ll solve2() { deque<int> q;//存前缀和的最小值 q.push_back(0); ll sum=0; int l,r;//最小值对应的连续子区间的左右端点 l=0; r=0; for(int i=1;i<=n;i++) { while(q.empty()==0&&s[i]>=s[q.back()]) { q.pop_back(); } if(q.empty()==0) { if(sum>(s[i]-s[q.front()])) { sum=s[i]-s[q.front()]; l=q.front(); r=i; } } q.push_back(i); } ll res=0; res=s[l]+s[n]-s[r]+sum*c; return res>s[n]?res:s[n]; } int main() { std::ios::sync_with_stdio(false); cin.tie(0); cin>>n>>c; for(int i=1;i<=n;i++) { cin>>a[i]; s[i]=s[i-1]+a[i]; } a[0]=0; s[0]=0; ll ans1=solve1(); ll ans2=solve2(); ans=max(ans1,ans2); cout<<ans; }
- 1
Information
- ID
- 2819
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- # Submissions
- 1
- Accepted
- 1
- Uploaded By