hdu1003最大连续子段和

此题有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;
    }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值