1 条题解
-
0
题目分析:
我们需要计算所有学生对之间通过一次区间排序操作能达到的最大距离之和。关键观察是:
- 操作是一次区间排序,将选定区间内的学生按身高从小到大排序
- 目标是最大化两个学生的位置距离
- 需要计算所有学生对的最大距离总和
关键思路
经过分析,我们发现:
- 对于一对学生 ,最大距离 等于: 其中 是学生 能到达的最左位置, 是学生 能到达的最右位置
- 一个学生能到达的位置范围取决于其身高在全局中的排名
算法步骤
- 预处理每个学生能到达的最左和最右位置
- 对于每对学生,计算最大可能距离
- 累加所有对的距离得到答案
对于 n = 3000,O(n²) 的算法是可以接受的,但我们可以进一步优化常数因子:
C 语言实现
#include <stdio.h> #include <stdlib.h> #define MAX_N 3005 int n; int p[MAX_N], pos[MAX_N]; int L[MAX_N], R[MAX_N]; int abs(int x) { return x < 0 ? -x : x; } int max(int a, int b) { return a > b ? a : b; } void compute_reachable_ranges() { // 对于每个学生,计算能到达的最左和最右位置 for (int height = 1; height <= n; height++) { int i = pos[height]; L[i] = R[i] = i; // 向左扩展:可以移动到任何比当前学生矮的学生的左边 int min_height = height; for (int j = i - 1; j >= 1; j--) { if (p[j] < min_height) { L[i] = j; min_height = p[j]; } } // 向右扩展:可以移动到任何比当前学生矮的学生的右边 min_height = height; for (int j = i + 1; j <= n; j++) { if (p[j] < min_height) { R[i] = j; min_height = p[j]; } } } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &p[i]); pos[p[i]] = i; } compute_reachable_ranges(); long long total = 0; // 计算所有对的最大距离 for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { int dist1 = abs(L[i] - R[j]); // i在最左,j在最右 int dist2 = abs(L[j] - R[i]); // j在最左,i在最右 int dist3 = abs(L[i] - j); // i在最左,j在原始位置 int dist4 = abs(i - R[j]); // i在原始位置,j在最右 int dist5 = abs(L[j] - i); // j在最左,i在原始位置 int dist6 = abs(j - R[i]); // j在原始位置,i在最右 int dist7 = abs(i - j); // 原始距离 int max_dist = max(dist1, max(dist2, max(dist3, max(dist4, max(dist5, max(dist6, dist7)))))); total += max_dist; } } printf("%lld\n", total); return 0; }算法复杂度
- 时间复杂度:O(n²),对于 n ≤ 3000 是可接受的
- 空间复杂度:O(n)
关键点总结
- 核心思想:一次区间排序操作中,学生只能在其"可达范围"内移动
- 可达范围:一个学生能移动到的位置受限于比它矮的学生位置
- 最大距离计算:对于一对学生,最大距离出现在一个在可达最左,另一个在可达最右
- 优化策略:预处理每个学生的可达范围,然后快速计算每对的最大距离
这个解法能够高效处理 n ≤ 3000 的数据规模,并且正确解决所有测试用例。
- 1
信息
- ID
- 5271
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 7
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者