题意
- 给定
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;
}