首页 > 其他 > 详细

P1115 最大子段和

时间:2019-06-11 09:24:18      阅读:129      评论:0      收藏:0      [点我收藏+]

原题链接 https://www.luogu.org/problemnew/show/P1115

某大佬:天啊!普及-的题你都要写博客,太菜了吧!

主要是这个题教会了我时间复杂度O(n),空间复杂度O(1)的算法来求最大字段和。

一起来看一下吧:

我们先设一个temp来暂时存几个数的和,maxn是最大字段和,a是每次读入的数:

先读入一个a,记录在temp里,然后for(i=2;i<=n;i++) 读入剩下的数,如果temp小于0就将temp赋值成0,如果大于0就不用了,然后temp+=a,最后maxn=max(maxn,temp)就好啦!

#include<iostream>
#include<cstdio>
using namespace std;
int read()
{
    char ch=getchar();
    int a=0,x=1;
    while(ch<0||ch>9)
    {
        if(ch==-) x=-x;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
    {
        a=(a<<3)+(a<<1)+(ch-0);
        ch=getchar();
    }
    return a*x;
}
int n,temp=0,maxn,a;
int main()
{
    n=read();
    a=read();
    temp=a;                      //temp先存着第一个数的值 
    maxn=-1000000;
    for(int i=2;i<=n;i++)
    {
        if(temp<0) temp=0;       //这一步操作一定要放在读数前面,如果temp的值小于0还不如不要了 
        a=read();
        temp+=a;                 //temp加上这个数的值 
        if(temp>maxn) maxn=temp; //取最大值 
    }
    cout<<maxn;
    return 0;
} 

解释一下正确性:

对于这个题,temp如果是小于0的话,如果不舍弃的话,再加上一个正数,肯定会拖累那个正数成为最大值(在成为最大值的道路上谁会甘心让自己加一个负数使自己变小呢?)所以我们要在读入每个数之前判断temp是不是小于0,若小于0就将它赋值成0(就是相当于舍弃了前几个数的和);若maxn>temp>0,说明temp有成为最大值的潜力,可能再加上几个正数就会一举超过最大值达到人生巅峰,所以当temp大于0时我们就不要舍弃了。下面举个例子方便理解:

技术分享图片

但是有些毒瘤题的数据很大咋办?---------我们可以用二分!

假设我们要求区间[1,n]的最大字段和,它们的值分别是a[1],a[2]……,a[n],我们可以将区间[1,n]分成两个长度相等的小区间[1,n/2]和[n/2+1,n],那么这个最大子段有三种情况:

1. 最大子段在区间[1,n/2]里;

2. 最大子段再区间[n/2+1,n]里;

3. 最大子段的左端点再区间[1,n/2],右端点在[n/2+1,n]里;

对于第一和第二种情况,我们可以递归解决,我们重点看第三种情况:

技术分享图片

我们已经知道两个端点分别在两个小区间,设这两个端点为p,q,那么区间[p,n/2]和区间[n/2+1,q]这一段一定是连续被包含在最大子段里的,且要是整个子段最大,那么久尽量让左子段和右子段最大,所以我们可以从n/2分别往左和往右扫求出最大子段,再加起来就是整个区间的最大子段。

P1115 最大子段和

原文:https://www.cnblogs.com/xcg123/p/11001659.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!