题解:学而思编程 数组推导
【题目来源】
学而思编程:数组推导
【题目描述】
已知数组 \(a\) 和数组 \(b\) 是都是由 \(n\) 个非负整数组成的数组,数组 \(b\) 中每一个元素 \(b_i\) 为数组 \(a\) 中前 \(i\) 个元素的最大值,如表达式所示:\(b_i = max\{a_1, a_2, \ldots, a_i\}\)
我们用 \(sum = a_1 + a_2 + \ldots + a_n\) 表示数组 \(a\) 的 \(n\) 个元素之和。
现在告诉你 \(b\) 数组,请你根据 \(b\) 数组反推 \(a\) 数组。\(a\) 数组可能并不唯一,请你根据 \(a\) 数组的所有可能情况给出 \(sum\) 的最小值和最大值分别是多少。
【输入】
第一行一个整数 \(n\);
第二行 \(n\) 个整数 \(b_1, b_2, \ldots, b_n\)。
【输出】
一行两个空格隔开的整数。
【输入样例】
6
0 0 5 5 10 10
【输出样例】
15 30
【核心思想】
-
问题分析:已知数组 \(b\) 满足 \(b_i = \max(a_1, a_2, \ldots, a_i)\),即 \(b\) 是 \(a\) 的前缀最大值数组。要求根据 \(b\) 反推所有可能的 \(a\),并求 \(sum(a)\) 的最小值和最大值。这是一个前缀最大值逆推 + 极值分析问题,关键在于理解 \(b\) 的非降性质以及 \(a_i\) 的取值约束。
-
算法选择:
- 最大值分析:\(a_i\) 最大可取 \(b_i\),此时 \(sum = \sum_{i=1}^{n} b_i\)
- 最小值分析:\(a_i\) 在满足前缀最大值约束下取最小值,仅在 \(b_i\) 首次出现时取 \(b_i\),其余位置取 \(0\)
-
关键步骤:
- 初始化:读取 \(n\) 和数组 \(b[1..n]\)
- 计算最大值:
mx = 0- 遍历 \(i\) 从 \(1\) 到 \(n\):
mx += b[i]:每个 \(a_i\) 最大取 \(b_i\),总和即为所有 \(b_i\) 之和
- 计算最小值:
mn = 0- 遍历 \(i\) 从 \(1\) 到 \(n\):
- 若 \(b_i \neq b_{i-1}\)(\(b_i\) 首次出现,即前缀最大值上升):
mn += b[i]:该位置 \(a_i\) 必须取 \(b_i\) 才能使前缀最大值达到 \(b_i\)
- 否则(\(b_i = b_{i-1}\),前缀最大值不变):
- \(a_i\) 可取 \(0\)(最小),不增加总和
- 若 \(b_i \neq b_{i-1}\)(\(b_i\) 首次出现,即前缀最大值上升):
- 输出
mn和mx
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),两次线性遍历
- 空间复杂度:\(O(n)\),存储数组 \(b[1..n]\)
-
前缀最大值逆推的核心思想:
- \(b\) 的非降性:由定义 \(b_i = \max(b_{i-1}, a_i)\) 可知 \(b\) 单调不减,且 \(b_i \geq a_i\)
- 最大值构造:令所有 \(a_i = b_i\),显然满足 \(b_i = \max(a_1, \ldots, a_i)\),此时 \(sum\) 最大
- 最小值构造:当 \(b_i = b_{i-1}\) 时,说明前 \(i-1\) 个元素中已有值为 \(b_i\) 的元素,因此 \(a_i\) 可取 \(0\) 而不影响前缀最大值;仅当 \(b_i > b_{i-1}\) 时,\(a_i\) 必须取 \(b_i\) 才能使前缀最大值上升
- 约束传递:\(b_i\) 的变化点唯一确定了 \(a\) 中必须非零的位置,其余位置均可取 \(0\)
- 适用于"前缀最值逆推 + 极值构造"类问题,通过分析变化点确定强制取值位置
【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 10;
int n, a[N], mx, mn;
signed main()
{
cin >> n; // 输入序列长度
for (int i = 1; i <= n; i++)
{
cin >> a[i]; // 输入序列
mx += a[i]; // 计算最大值:所有元素之和
}
// 计算最小值
for (int i = 1; i <= n; i++)
{
if (a[i] != a[i - 1]) // 如果当前元素与前一个不同
{
mn += a[i]; // 加入最小值
}
}
cout << mn << " " << mx << endl; // 输出最小值最大值
return 0;
}
【运行结果】
6
0 0 5 5 10 10
15 30
浙公网安备 33010602011771号