题解 【洛谷P1115】最大子段和

这是一道枚举经典题。

本题有三种作法,各位须要根据每一个题的数据范围来决定本身用哪一种方法。spa

本题解中统一设最大和为Max。code

方法1、 枚举子序列,从起点到终点求和。时间复杂度:O(n^3)

咱们能够枚举它的子序列,也就是枚举它的长度、起点和终点。咱们不妨设长度为i,起点为j,终点为k,当前子序列的和为s。因而咱们就有了下列核心代码:blog


Max=a[1];//最大和初始化为第一个数
    for(i=1;i<=n;i++)//枚举长度
        for(j=i;j<=n;j++){//枚举起点
            s=0;//当前序列和初始化为0
            for(k=i;k<=j;k++)//枚举终点
                s+=a[k];//计算和
            if(s>Max)Max=s;//比较
 } printf("%d",Max);//输出

 


这种方法在时限1s的题目中只能经过n<=450的范围。class

可是本题的序列长度n<=200000。方法

因此采用该方法超时。总结

方法2、先求前缀和,再枚举。时间复杂度:O(n^2)

咱们能够先求出从第一个数到当前数的和,而后枚举起点和终点,计算每个子序列的和。因而咱们就有了下列核心代码:数据


memset(s,0,sizeof(s));//初始化前缀和
    for(i=1;i<=n;i++)s[i]=s[i-1]+a[i];//计算前缀和
    Max=a[i];//初始化最大值为第一个数
    for(i=1;i<=n;i++) for(j=i;j<=n;j++) Max=max(Max,s[j]-s[i-1]);//枚举起点和终点。 //注意是i-1!由于计算从第i个数开始的和须要减去前i-1个数的和
    printf("%d",Max);

 


怎么有点像DP?di

这种方法在时限1s的题目中只能勉强经过n<=10000的范围。时间

可是本题的序列长度n<=200000。co

因此采用该方法也超时。

方法3、直接从头开始计算和,并每次记录最大和。时间复杂度:O(n)

不妨设s为以第i个数结尾的最大和,并每次计算和。

若当前和比最大值大,就更新最大值。

若当前和比0小,就把和清0。

核心代码:


scanf("%d",&n); s=0; Max=-2e9; for(i=1;i<=n;i++){ scanf("%d",&a); s+=a; if(s>Max)Max=s; if(s<0)s=0; } printf("%d",Max);

 


这种方法在时限1s的题目中能勉强经过n<=100000000的范围。

因为本题的序列长度n<=200000。

因此能够采用这种方法。

总结:必定要明白第三种方法的道理,而且能本身编写代码,这样水平才能有所提高。

相关文章
相关标签/搜索