题解:学而思编程 数列调整
【题目来源】
学而思编程:数列调整
【题目描述】
回文数列是一类特殊的数列。简单来说,如果一个数列是回文数列,那么它与它颠倒过来的数列是一样的,例如:
\(1,2,3,4,5,4,3,2,1\)
\(5,4,3,2,1,1,2,3,4,5\)
现在小猴有一个 \(n\) 项的数列 \(a_1,a_2,\dots,a_n\),你可以进行任意多次操作:选择任意一项,将其数值加 \(1\) 或者减 \(1\)。
请问最少需要多少次操作,才可以将这个数列变成一个回文数列。
【输入】
第一行一个正整数 \(n\);
第二行 \(n\) 个正整数,从左到右依次表示数列对应项 \(a_1,a_2,\dots,a_n\) 的值。
【输出】
一个整数表示答案。
【输入样例】
3
1 2 3
【输出样例】
2
【核心思想】
-
问题分析:给定长度为 \(n\) 的数列 \(a_1, a_2, \ldots, a_n\),每次操作可将任意元素加 \(1\) 或减 \(1\),求最少操作次数使数列变为回文。这是一个贪心配对问题,关键在于识别回文的对称性约束,将问题转化为对称位置差的绝对值之和。
-
算法选择:
- 对称位置配对:回文数列满足 \(a_i = a_{n-i+1}\),因此只需考虑对称位置对
- 绝对值最小化:使 \(a_i\) 和 \(a_{n-i+1}\) 相等的最少操作次数为 \(|a_i - a_{n-i+1}|\)
-
关键步骤:
- 初始化:读取 \(n\)(数列长度)和数组 \(a[1..n]\)
- 对称配对求和:
- 遍历 \(i\) 从 \(1\) 到 \(\lfloor n/2 \rfloor\):
ans += |a_i - a_{n-i+1}|:每对对称位置需要 \(|a_i - a_{n-i+1}|\) 次操作才能使两者相等
- 遍历 \(i\) 从 \(1\) 到 \(\lfloor n/2 \rfloor\):
- 输出
ans
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\),遍历前一半元素
- 空间复杂度:\(O(n)\),存储数列数组
-
贪心对称配对的核心思想:
- 回文约束分解:回文条件 \(a_i = a_{n-i+1}\) 将 \(n\) 个变量约束为 \(\lfloor n/2 \rfloor\) 个独立的对称对,中间元素(\(n\) 为奇数时)无需调整
- 单对最优性:对于一对对称位置 \((a_i, a_{n-i+1})\),使两者相等的最优目标值为两者之间任意值,最少操作次数恒为 \(|a_i - a_{n-i+1}|\)(与目标值选择无关)
- 对间独立性:不同对称对的调整互不干扰,总操作次数为各对之和,贪心累加即得全局最优
- 操作语义:每次 \(+1\) 或 \(-1\) 操作使一个元素向目标值靠近一步,\(|a_i - a_{n-i+1}|\) 恰好是将较小者增加到较大者(或两者调整到中间某值)所需的最少步数
- 适用于"回文变换 + 单元素单位调整"类问题,对称配对可将复杂全局优化分解为独立子问题
【解题思路】

【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10; // 数组大小
long long n, ans, val[N]; // n: 数组长度, ans: 结果, val: 数组
int main()
{
cin >> n; // 输入数组长度
for (int i = 1; i <= n; i++) // 输入数组元素
{
cin >> val[i];
}
// 计算对称位置差的绝对值之和
for (int i = 1; i <= n / 2; i++) // 遍历前一半元素
{
// 计算第i个元素和对称位置元素的差的绝对值
// 对称位置:i 和 n-i+1
ans += abs(val[i] - val[n - i + 1]);
}
cout << ans << endl; // 输出结果
return 0;
}
【运行结果】
3
1 2 3
2
浙公网安备 33010602011771号