题意
- 给定
K个数的序列,求其最大子串和(一般来说,子串表示必须连续,而子序列表示可以不连续),并输出最大子串的首尾元素(不是下标)。
注意
- 以下标i为尾的最大子串的选择只有两种
- 本身(元素
a[i]本身) - 下标
i-1为尾的最大子串(若存在)加上本身。
- 本身(元素
- 如何证明?其实就是最优性原理。首先子串必然是连续的,设以下标
i-1为尾的最大子串为s0,以下标i为尾的最大子串为s,s为何不能选择s0的一部分或是s0加上更前面的?s若是选择s0的一部分,那么说明没有选择的一部分是负数,那么s0也不该选这部分,与假设矛盾。s若是选择s0以及更多,那么说明选择的更多的比只选择s0更大,那么s0也该选这部分,与假设矛盾。- 然而,
s0若是负数,那么s就不该选s0
- 所以,首先
s一定包括a[i];其次,要么包括s0全部,要么不包括任何。 - 整个序列的最大子串必定以某一元素为尾,那么它就是所有以某元素为尾的最大子串中最大的那个。
- 这题还有个问题,如下,我理解的是,和相同情况下,首先选择
i小,若i一样,选择j小的。这就意味着最大子串前面的0也算上(若有),而最大子串后面的0不算(若有)。(有点无聊233)
In case that the maximum subsequence is not unique, output the one with the smallest indices i and j (as shown by the sample case).
单词
- indice 下标
代码
#include<iostream>
using namespace std;
const int maxi = 10000;
int a[maxi];
int p[maxi];
int sum[maxi];
int main()
{
int n;
scanf_s("%d",&n);
for (int i = 0; i < n; i++)
scanf_s("%d", &a[i]);
for (int i = 0; i < n; i++)
{
if (a[i] >= 0)
break;
if (i == n - 1)
{
printf("0 %d %d", a[0], a[i]);
return 0;
}
}
p[0] = 0;
sum[0] = a[0];
for (int i = 1; i < n; i++)
{
if (sum[i - 1] + a[i] >= a[i]) //// >= 尽力扩展更多的前0,使得首结点下标最小
{
p[i] = p[i - 1];
sum[i] = sum[i - 1] + a[i];
}
else
{
p[i] = i;
sum[i] = a[i];
}
}
int m = sum[0];
int k = 0;
for (int i = 1; i < n; i++)
{
if (sum[i] > m) //// > 后0不需要,更不需要之后的相等的最大子序列,使得尾结点下标最小
{
m = sum[i];
k = i;
}
}
printf("%d %d %d", m, a[p[k]], a[k]);
return 0;
}

本文探讨了最大子串和问题的解决方案,通过分析最优子结构特性,提出了一个高效的算法实现,并提供了完整的C++代码示例。文章还讨论了特殊情况处理,确保在多个最大子串的情况下返回具有最小下标的子串。
735

被折叠的 条评论
为什么被折叠?



