FIrst:无限制最大子段和问题 时间复杂度:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
long long f[N];
int main(){
int n;
scanf("%d",&n);
long long res=-0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++){
long long x;
scanf("%lld",&x);
f[i]=max(f[i-1],(long long)0)+x;
res=max(res,f[i]);
}
printf("%lld\n",res);
return 0 - 0;
}
Second:子段长度不大于m的最大子段和问题 时间复杂度:
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
int n,m;
long long sum[N];
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
long long x;
scanf("%lld",&x);
sum[i]=x+sum[i-1];
}
deque<long long> q;
q.push_back(0);
long long res=-0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++){
while(q.size()&&i-q.front()>m) q.pop_front();
res=max(res,sum[i]-sum[q.front()]);
while(q.size()&&sum[q.back()]>=sum[i]) q.pop_back();
q.push_back(i);
}
printf("%lld\n",res);
return 0 - 0;
}
Third:长度不小于m的最长子段和问题 时间复杂度:
#include<bits/stdC++.h>
using namespace std;
const int N=2e5+10;
int sum[N],f[N],g[N];
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
f[i]=max(f[i-1],0)+x;
sum[i]=sum[i-1]+x;
}
int res=-0x3f3f3f3f;
for(int i=1;i+m-1<=n;i++){
g[i]=max(f[i-1],0)+sum[i+m-1]-sum[i-1];
res=max(g[i],res);
}
printf("%d\n",res);
return 0 - 0;
}
Foruth:环状最大子段和问题 时间复杂度:
1.将序列倍长,就可以做一遍长度不大于m的最大子段和
2.先正着求一遍最大子段和,考虑子段是否过端点,过端点就取反,然后求一个最小子段和,不过端点就没有影响。
Fifth:环状最大两段子段和 时间复杂度: /
考虑破环成链,枚举破坏的断点,在链上求最大两段子段和;维护一个为以结尾的最大子段和,一个为以开头的最大子段和;(其实就是倒着求一遍)复杂度;
对于答案可能有的所有情况,一种是有一段跨过了端点,另一种是没有跨过端点;所以可以先求一遍两段最大子段和,再对整个序列取反,再求一遍(这时其实就是求出两段的最小子段和,用总和减去后就是跨过端点的两段最大子段和),这时把两种情况取一个;
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int s[N],front[N],back[N];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
memset(front,-0x3f,sizeof(front));
memset(back,-0x3f,sizeof(back));
int sum1=-2e9,sum2=-2e9,sum=0;
for(int i=1;i<=n;i++) front[i]=max(front[i-1],0)+s[i];
for(int i=1;i<=n;i++) front[i]=max(front[i-1],front[i]);
for(int i=n;i>=1;i--) back[i]=max(back[i+1],0)+s[i];
for(int i=n;i>=1;i--) back[i]=max(back[i+1],back[i]);
for(int i=1;i<n;i++) sum1=max(sum1,front[i]+back[i+1]);
int cnt=0;
for(int i=1;i<=n;i++){
if(s[i]>0) cnt++;
}
if(cnt<=1){
printf("%d\n",sum1);
return 0 - 0;
}
memset(front,-0x3f,sizeof(front));
memset(back,-0x3f,sizeof(back));
for(int i=1;i<=n;i++) sum+=s[i],s[i]=-s[i];
for(int i=1;i<=n;i++) front[i]=max(front[i-1],0)+s[i];
for(int i=1;i<=n;i++) front[i]=max(front[i-1],front[i]);
for(int i=n;i>=1;i--) back[i]=max(back[i+1],0)+s[i];
for(int i=1;i<n;i++) sum2=max(sum2,front[i]+back[i+1]);
sum2=sum+sum2;
int res=max(sum1,sum2);
printf("%d\n",res);
return 0 - 0;
}