题目相关
题目链接
AtCoder Beginner Contest 182 D 题,https://atcoder.jp/contests/abc182/tasks/abc182_d。
Problem Statement
Given is a number sequence A1,A2,A3,…,AN, which may contain negative elements.
On a number line, there is a robot at coordinate 0 . It will do the following actions in order:
- Move A1 in the positive direction.
- Move A1 in the positive direction, and then move A2 in the positive direction.
- Move A1 in the positive direction, then move A2 in the positive direction, and then move A3 in the positive direction.
- ⋮
- Move A1 in the positive direction, then move A2 in the positive direction, then move A3 in the positive direction, …, …, and then move AN in the positive direction.
Find the greatest coordinate occupied by the robot from the beginning to the end of the process.
Input
Input is given from Standard Input in the following format:
N
A1 A2 A3 … AN
Output
Print the greatest coordinate occupied by the robot from the beginning to the end of the process.
Samples1
Sample Input 1
3
2 -1 -2
Sample Output 1
5
Explaination
The robot moves as follows:
- Move 2 in the positive direction, to coordinate 2.
- Move 2 in the positive direction, to coordinate 4. Then move −1 in the positive direction, to coordinate 3.
- Move 2 in the positive direction, to coordinate 5. Then move −1 in the positive direction, to coordinate 4. Then move −2 in the positive direction, to coordinate 2.
The greatest coordinate occupied during the process is 5, so we should print 5.
Samples2
Sample Input 2
5
-2 1 3 -1 -1
Sample Output 2
2
Samples3
Sample Input 3
5
-1000 -1000 -1000 -1000 -1000
Sample Output 3
0
Explaination
In this case, the initial coordinate 0 is the greatest coordinate occupied.
Constraints
- 1≤N≤200000
- −10^8≤Ai≤10^8
- All values in input are integers.
题解报告
题目翻译
给一个由 A1, A2, A3, ..., An 组成的序列,其中可能包括负数。有一个机器人在坐标 0 位置,机器人将按照顺序进行如下动作:
- 将 A1 向正方向移动。
- 将 A1 向正方向移动,接着将 A2 向正方向移动。
- 将 A1 向正方向移动,接着将 A2 向正方向移动,接着将 A3 向正方向移动。
- ...
- 将 A1 向正方向移动,接着将 A2 向正方向移动,接着将 A3 向正方向移动,...,...,最后将 An 向正方向移动。
请找出机器人能移动到最大坐标。
样例数据分析
样例数据 1
根据样例,序列 A 为 {2 -1 -2}。因为要移动,我们将数据做一个前缀和数组 nums(前缀和是常用的数据预处理技巧),这样数据变为 {0 2 1 -1}。同时我们来一个最大值数组 maxx,该数组保存前缀和前 i-1 个数据和 a[i] 的最大值。这样我们还有一个 maxx 数组 {0 2 2 2}。由于 n=3,因此机器人只能移动三次。这样我们利用下面的表格进行分析。
由于机器人只能向正方向移动,因此机器人每次可能的位置为:当前位置和可移动位置的最大值,也就是 ans=max(ans, pos+maxx[i]);
可移动位置就是当前位置加上 nums[i],也就是 pos = pos+nums[i];
ans | pos | nums[i] | maxx[i] | now+maxx[i] | |
初始 | 0 | 0 | 0 | 0 | |
1 | 2 | 2 | 2 | 2 | 0+2=2 |
2 | 4 | 3 | 1 | 2 | 2+2=4 |
3 | 5 | 4 | -1 | 2 | 3+2=5 |
这样,经过三次移动后,机器人的位置 ans=5。
样例数据 2
根据样例,序列 A 为 {-2 1 3 -1 -1}。我们将数据做一个前缀和数组 nums,这样数据变为 {0 -2 -1 2 1 0}。同时我们来一个最大值数组 maxx,该数组保存前缀和前 i-1 个数据和 a[i] 的最大值。这样我们还有一个 maxx 数组 {0 0 0 2 2 2}。由于 n=5,因此机器人只能移动五次。这样我们利用下面的表格进行分析。
ans | pos | nums[i] | maxx[i] | now+maxx[i] | |
初始 | 0 | 0 | 0 | 0 | |
1 | 0 | -2 | -2 | 0 | 0 |
2 | 0 | -3 | -1 | 0 | -3 |
3 | 0 | -1 | 2 | 2 | -1 |
4 | 1 | 0 | 1 | 2 | 1 |
5 | 2 | 0 | 0 | 2 | 2 |
这样,经过五次移动后,机器人的位置 ans=2。
样例数据 3
根据样例,序列 A 为 {-1000 -1000 -1000 -1000 -1000}。我们将数据做一个前缀和数组 nums,这样数据变为 {0 -1000 -2000 -3000 -4000 -5000}。同时我们来一个最大值数组 maxx,该数组保存前缀和前 i-1 个数据和 a[i] 的最大值。这样我们还有一个 maxx 数组 {0 0 0 0 0 0}。由于 n=5,因此机器人只能移动五次。这样我们利用下面的表格进行分析。
ans | pos | nums[i] | maxx[i] | now+maxx[i] | |
初始 | 0 | 0 | 0 | 0 | |
1 | 0 | -1000 | -1000 | 0 | 0 |
2 | 0 | -3000 | -2000 | 0 | -1000 |
3 | 0 | -6000 | -3000 | 0 | -3000 |
4 | 0 | -10000 | -4000 | 0 | -6000 |
5 | 0 | -15000 | -5000 | 0 | -10000 |
这样,经过五次移动后,机器人的位置 ans=0。
题目分析
从上面的数据分析可以看出,我们通过前缀和来降低运算复杂度,维护一个 maxx 数组来确认最优的位置。为了更清楚的看出数据,这样我们可以写出以下核心:
a[i] 用来保存原始数据
nums[i] = a[0]+a[1]+...+a[i] = nums[i-1]+a[i];
maxx[i] = max(nums[0], nums[1], ..., nums[i]) = max(maxx[i-1], nums[i]);
机器人可以到的位置是 nums[0]+nums[1]+nums[2]+...+nums[n];
最大的距离是 max(0, maxx[0], nums[0]+maxx[1], nums[0]+nums[1]+maxx[2], ...)。
数据分析
N 的范围是 [1, 2e5],数据 Ai 范围是 [-1e8, 1e8],因此最大的数据是 2e5*1e8=2e13,因此需要使用 long long 来表示。
AC 参考代码
//https://atcoder.jp/contests/abc182/tasks/abc182_d
//D - Wandering
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e6+4;
LL nums[MAXN];//采用前缀和预处理
LL maxx[MAXN];
int main() {
#if 1
//提交OJ使用快读
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
LL n;
cin>>n;
for (LL i=1; i<=n; i++) {
cin>>nums[i];
//计算前缀和
nums[i] += nums[i-1];
maxx[i] = max(maxx[i-1], nums[i]);
}
LL ans=0;//当前robot位置
LL pos=0;
for (LL i=1; i<=n; i++) {
ans=max(ans, pos+maxx[i]);
pos += nums[i];
}
cout<<ans<<"\n";
return 0;
}
时间复杂度
O(N)。