洛谷P1115

题很简单,但是方法值得保留

题目描述

给出一段序列,选出其中连续且非空的一段使得这段和最大。

输入格式

第一行是一个正整数N,表示了序列的长度。
第二行包含N个绝对值不大于1000000的整数,描述这段序列。

输出格式

连续最大和

法一(最朴素的算法)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
const int Minn=-0x3f3f3f;
int data[N],sum[N],bigsum[N];
int main()
{
	int n=0,minn=0,mixx=Minn;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>data[i];
		sum[i]=sum[i-1]+data[i];
	}
	minn=min(sum[1],minn);
	bigsum[1]=data[1];
	for(int i=2;i<=n;i++)
	{
		bigsum[i]=sum[i]-minn;
		minn=min(sum[i],minn);
	}
	for(int i=1;i<=n;i++)
	  mixx=max(mixx,bigsum[i]);
	cout<<mixx;
	return 0;

法二(滚动数组,值得保留)

如果前缀和sum变成了负数,那么下一个数就不需要前面的数了(因为还不如只选它一个),这时把sum置为0,再继续累加。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
const int Minn=-0x3f3f3f;
int f[2],sum;
int main()
{
	int n;
	cin>>n;
	cin>>f[1];
	sum=f[1];
	for(int i=2;i<=n;i++)
	{
		if(sum<0)sum=0;
		scanf("%d",&f[i%2]);
		sum+=f[i%2];
		f[i%2]=max(f[(i-1)%2],sum);
	}
	cout<<f[n%2];
	return 0;
}

法三(分治)

首先,假定有区间[l,r],其中间位置为mid,其最大子段为[i,j]。那么显然,i和j必定符合下列三种情况之一:
1.l ≤ i ≤ j ≤ mid
2.i ≤ mid < j ≤ r
3.mid < i ≤ j ≤ r

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
const int Minn=-0x3f3f3f;
int data[N];
int SUM(int l,int r)
{
	if(l==r)
		return data[l];
	int mid=(l+r)>>1;
	int sum=0,suml=Minn,sumr=Minn;
	for(int i=mid;i>=l;i--)
	{
		sum+=data[i];
		suml=max(sum,suml);
	}
	sum=0;
	for(int i=mid+1;i<=r;i++)
	{
		sum+=data[i];
		sumr=max(sum,sumr);
	}
	return max(max(SUM(l,mid),SUM(mid+1,r)),suml+sumr);
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d",&data[i]);
	cout<<SUM(1,n);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值