HDU 1003 最大子序列和

这道题有两种做法
原题如下:
在这里插入图片描述
题目大意:
给你n个无序的数,求出最大的字序列的和及其对应的下标;
例如:6 -1 5 4 -7
最大的子序列和不就是6±1+5+4=14;从1开始到4结束;

emmm就是这个意思;
那么怎么做呢
先介绍比较冗长一点的做法,就是用分治法,将问题划分为三个部分,左半边的最大子序列和,右半边的最大子序列和,中间部分的最大子序列和,这三者的最大值就是答案啦。
这个问题对于我来说也是困扰了很久,我也想不通、、、、、、
看一下代码吧:


```cpp
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 100005;
int a[maxn];
int maxleft, maxright, maxsum, cnt=1;
int cmp(int a, int b, int c)
{
	if (a >= b && a >= c)	return 1;
	if (b >= a && b >= c)	return 2;
	if (c >= a && c >= b)	return 3;
}
int function(int left, int right, int* l, int* r)
{
	if (left == right)
	{
		*l = *r = left;
		return a[left];
	}
	int leftsum, rightsum;
	int ll, lr, rl, rr, thisleft, thisright;
	int mid = (left + right) / 2;
	leftsum = function(left, mid, &ll, &lr);
	rightsum = function(mid + 1, right, &rl, &rr);

	int leftbordersum = 0, leftmax = a[mid];
	thisleft = mid;
	for (int i = mid; i >= left; i--)
	{
		leftbordersum += a[i];
		if (leftbordersum > leftmax)
		{
			leftmax = leftbordersum;
			thisleft = i;
		}
	}
	int rightbordersum = 0, rightmax = a[mid + 1];
	thisright = mid + 1;
	for (int i = mid + 1; i <= right; i++)
	{
		rightbordersum += a[i];
		if (rightbordersum > rightmax)
		{
			rightmax = rightbordersum;
			thisright = i;
		}
	}
	int midsum = leftmax + rightmax;
	int flag = cmp(leftsum, midsum, rightsum);
	if (flag == 1)
	{
		*l = ll;
		*r = lr;
		maxsum = leftsum;
	}
	else if (flag == 2)
	{
		*l = thisleft;
		*r = thisright;
		maxsum = midsum;
	}
	else
	{
		*l = rl;
		*r = rr;
		maxsum = rightsum;
	}
	return maxsum;
}
int main()
{
	int t,n;
	scanf_s("%d", &t);
	while (t--)
	{
		scanf_s("%d", &n);
		for (int i = 0; i < n; i++)	scanf_s("%d", &a[i]);
		maxsum = a[0];
		maxleft = maxright = 0;
		maxsum=function(0, n - 1, &maxleft, &maxright);
		printf("Case %d:\n%d %d %d\n", cnt++,maxsum,maxleft+1,maxright+1);
		if (t)
			printf("\n");
	}
	return 0;
}

嗯大概就是这样,细节很多;

还有一个优化很高的解法:

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int a[maxn];
int main()
{
	int t,n;
	scanf_s("%d", &t);
	int cnt = 1;
	while (t--)
	{
		scanf_s("%d", &n);
		for (int i = 1; i <= n; i++)	scanf_s("%d", &a[i]);
		int left=1, right=1,temp=1;
		int maxsum = -99999, thissum = 0;
		for (int i = 1; i <= n; i++)
		{
			thissum += a[i];
			if (thissum > maxsum)
			{
				maxsum = thissum;
				left = temp;
				right = i;
			}
			if (thissum < 0)
			{
				thissum = 0;
				temp = i+1;
			}
		}
		printf("Case %d:\n%d %d %d\n", cnt++, maxsum, left, right);
		if (t)	printf("\n");
	}
	return 0;
}

意思就是不断更新下标,555这个方法太强了我只能叹为观止
qwq
我一时间好解释不清,等我今天晚上把它调试一下看看是什么意思我再来更新;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值