此题有o(n3)和o(n2)的做法,可定是TLE的
1.dp
d[i]=(d[i-1]+a[i]>a[i])?d[i-1]+a[i]:a[i],其中d[i]是以第i个元素结尾,的最大子段和。
试想,如果此时d[i-1]<0,那么不惯此时重新以a[i]的符号,以a[i]为起始点子段和肯定是最大的;如果此时d[i-1]的符号和a[i-1]的符号不确定,情况可能就有很多种
(1)d[i-1]>0, a[i]>0肯定是划算的
(2)d[i-1]=4 ,a[i]=-7,a[i+1]=11,那么加上a[i]就很划算,因为你能获得a[i+1]
...........
其实可不记录每一步的和,直接将d[i]用一个sum代替
#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=100005;
int arr[maxn];
int main()
{
//freopen("in.txt","r",stdin);
int T;
cin>>T;
for(int c=1;c<=T;++c){
int n,sum,maxsum,f,e,h,t;
cin>>n;
for(int i=0;i<n;++i){
cin>>arr[i];
}
sum=maxsum=arr[0];
f=t=h=e=0;
for(int i=1;i<n;++i){
if(sum+arr[i]<arr[i]){
sum=arr[i];
h=i;
}
else{
sum=sum+arr[i];
}
if(sum>maxsum){
maxsum=sum;
f=h;
e=i;
}
}
cout<<"Case "<<c<<":"<<endl;
cout<<maxsum<<" "<<f+1<<" "<<e+1<<endl;
if(c!=T)cout<<endl;
}
return 0;
}
2.分治
《算法竞赛入门经典》140页讲分治的时候提到了这种做法,效率为O(nlogn),但是没有找到好的方法记录区间,看别人的做法是新建了一个结构体记录的,先给出原始算法,以后再想想
(1)将区间划分成[x,mid],[mid+1,y],
(2)递归求解,分别求左边的最大和和右边的最大和
bisearch(a,l,mid,lsum);
bisearch(a,mid+1,r,rsum);
(2)合并
从中点mid开始,分别向左右求出最大连续和,ls=(..., mid-1,mid) rs=(mid, mid+1,....)
sum=max(sum,ls+rs)
for(int i=mid;i>=l;--i){
tmp+=a[i];
if(tmp>ls){
ls=tmp;
//x=i;
}
}
tmp=0;
for(int i=mid+1;i<r;++i){
tmp+=a[i];
if(tmp>rs){
rs=tmp;
//y=i;
}
}
sum=ls+rs;
if(sum<lsum){
sum=lsum;
// h=x;
}
if(sum<rsum){
sum=rsum;
//t=y;
}