1.分两种情况讨论:
1.不包含头尾;
d[i]=max(a[i],d[i-1]+a[i]);
maxx = max(maxx,d[i]);
2.包含头尾:
因为数列总和是一定的,当最大子数列包含头尾,最小子数列是除最大子数列外的连续数列和,不包含头尾,可以先对数列取反,求最大值。
d[i] = max((long long)a[i], d[i - 1] + a[i]);
maxx = max(sum+d[i]);
代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<math.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
const int N = 1e6 + 1000;
int a[N],n;
LL d[N];
LL maxx = 0,sum=0;
int main()
{
cin >> n;
rep(i, 1, n)
{
scanf("%d", &a[i]);
sum += a[i];
}
rep(i, 1, n)
{
d[i] = max((long long )a[i], d[i - 1] + a[i]);
maxx = max(maxx,d[i]);
}
rep(i, 1, n)
a[i] *= -1;
rep(i, 1, n)
{
d[i] = max((long long)a[i], d[i - 1] + a[i]);
maxx = max(maxx, sum+d[i]);
}
cout << maxx << endl;
return 0;
}
2.用双端队列+前缀和:
对于环形问题,一般可以通过a[i+n]=a[i]转化为一维数组问题;
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<map>
#include<math.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
const int N = 2e6 + 1000;
LL a[N],n;
LL maxx = 0,sum=0;
int head, ed, q[N];
int main()
{
cin >> n;
rep(i, 1, n)
{
scanf("%lld", &a[i]);
a[i+n] = a[i];
}
rep(i, 1, 2 * n)
a[i] += a[i - 1];
rep(i,1,2*n)
{
while (head <= ed && a[i] <= a[q[ed]]) ed--;//保持队列头部对应前缀和最小
while (head <= ed && i - q[head]> n) head++;//维护长度
q[++ed] =i;
maxx = max(maxx,a[i] - a[q[head]]);
}
cout << maxx << endl;
return 0;
}