跳跳!

GitHub跳转原题关系图返回列表

排序后从地面先跳最高石头,再在剩余石头中交替跳最低和最高,让相邻高度差尽量大。

OJ: luogu

题目 ID: P4995

难度:普及-

标签:贪心排序双指针python

日期: 2026-01-02 23:14

题意

n 块高度互不相同的石头,地面高度为 0。从高度 x 跳到高度 y 的体力是 (x-y)^2。要把每块石头恰好跳一次,最后停在任意石头上,求最大总耗费。

思路

体力是高度差的平方,高度差越大收益越大。因此应该让跳跃顺序尽量在高低两端之间来回切换。

把高度排序后:

  1. 第一跳从地面 0 到最高石头,收益最大;
  2. 接下来从最高跳到最低;
  3. 再从最低跳到次高;
  4. 再从次高跳到次低;
  5. 如此交替,直到所有石头都跳完。

用双指针实现:right 指向当前最高,left 指向当前最低。每轮先跳 right,再跳 left

样例 6 3 5 排序后是 3 5 6

跳跃 高度变化 体力
1 0 -> 6 36
2 6 -> 3 9
3 3 -> 5 4
合计 49

Python 知识

  • diff * diffdiff ** 2 更贴近竞赛里“平方”的写法,也避免浮点参与。
  • Python int 不会像 C++ int 一样溢出,但仍要保持线性计算。
  • 双指针每跳到一块石头,就移动对应端点。

代码

python
import sys


def main():
    data = list(map(int, sys.stdin.buffer.read().split()))
    n = data[0]
    heights = data[1:1 + n]
    heights.sort()

    left = 0
    right = n - 1
    current = 0
    answer = 0

    while left <= right:
        diff = heights[right] - current
        answer += diff * diff
        current = heights[right]
        right -= 1

        if left > right:
            break

        diff = heights[left] - current
        answer += diff * diff
        current = heights[left]
        left += 1

    print(answer)


if __name__ == "__main__":
    main()
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */

/* P4995 跳跳! */
/* 排序后交替跳最高和最低,让相邻高度差尽量大。 */

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 305;

int n;
int h[MAXN]; // 石头高度

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> h[i];
    }

    // 高度排序
    sort(h + 1, h + n + 1);

    int left = 1, right = n;
    int cur = 0; // 当前所在高度,从地面 0 开始
    long long ans = 0;

    while (left <= right) {
        // 跳到当前最高的石头
        long long diff = h[right] - cur;
        ans += diff * diff;
        cur = h[right];
        right--;

        if (left > right) break;

        // 跳到当前最低的石头
        diff = h[left] - cur;
        ans += diff * diff;
        cur = h[left];
        left++;
    }

    cout << ans << "\n";
    return 0;
}

复杂度

排序复杂度是 O(nlogn)O(n \log n),跳跃模拟是 O(n)O(n)

空间复杂度是 O(n)O(n)

总结

这题不是模拟任意跳法,而是利用平方函数偏爱大差值的特点,让跳跃顺序在当前最高和当前最低之间交替。