这道题有两种做法
原题如下:
题目大意:
给你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
我一时间好解释不清,等我今天晚上把它调试一下看看是什么意思我再来更新;