P4995 跳跳!

题目描述

你是一只小跳蛙,你特别擅长在各种地方跳来跳去。

这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i i i 块的石头高度为 h i h_i hi,地面的高度是 h 0 = 0 h_0 = 0 h0=0。你估计着,从第 i i i 块石头跳到第 j j j 块石头上耗费的体力值为 ( h i − h j ) 2 (h_i - h_j) ^ 2 (hihj)2,从地面跳到第 i i i 块石头耗费的体力值是 ( h i ) 2 (h_i) ^ 2 (hi)2

为了给小 F 展现你超级跳的本领,你决定跳到每个石头上各一次,并最终停在任意一块石头上,并且小跳蛙想耗费尽可能多的体力值。

当然,你只是一只小跳蛙,你只会跳,不知道怎么跳才能让本领更充分地展现。

不过你有救啦!小 F 给你递来了一个写着 AK 的电脑,你可以使用计算机程序帮你解决这个问题,万能的计算机会告诉你怎么跳。

那就请你——会写代码的小跳蛙——写下这个程序,为你 NOIp AK 踏出坚实的一步吧!

输入格式

输入一行一个正整数 n n n,表示石头个数。

输入第二行 n n n 个正整数,表示第 i i i 块石头的高度 h i h_i hi

输出格式

输出一行一个正整数,表示你可以耗费的体力值的最大值。

输入输出样例 #1

输入 #1

2
2 1

输出 #1

5

输入输出样例 #2

输入 #2

3
6 3 5

输出 #2

49

说明/提示

样例解释

两个样例按照输入给定的顺序依次跳上去就可以得到最优方案之一。

数据范围

对于 1 ≤ i ≤ n 1 \leq i \leq n 1in,有 0 < h i ≤ 1 0 4 0 < h_i \leq 10 ^ 4 0<hi104,且保证 h i h_i hi 互不相同。

对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n3

对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n10

对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n20

对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n50

对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n300

题解分析

小跳蛙需要从地面(高度为0)出发,依次跳到每个石头各一次,最终停在任意一块石头上。每次跳跃的体力消耗为两石头高度差的平方。目标是找到一种跳跃顺序,使得总耗费体力值最大

解题思路

贪心策略

要使总体力消耗最大,应最大化每次跳跃的高度差。因此:

  1. 将石头按高度排序
  2. 采用高低交替跳跃的策略:
    • 从地面跳到最高的石头
    • 从最高跳到最低
    • 从最低跳到次高
    • 依此类推…

正确性证明

  • 平方函数是凸函数,高度差越大,增量越大
  • 这种交替跳跃方式能保证每次跳跃都尽可能产生最大高度差
  • 数学归纳法可证明这是全局最优解

代码实现分析

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
long long a[N], n;

int main() {
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    sort(a + 1, a + n + 1);  // 升序排序
    
    int l = 0, h = n;        // l指向最低,h指向最高
    long long ans = 0;
    bool flag = true;        // 标记跳跃方向
    
    while(l < h){
		if(flag){
			// 跳到低的 
			ans +=pow(a[l++] - a[h], 2);
		}else{
			// 跳到高的
			ans +=pow(a[l] - a[h--], 2); 
		}
		flag = !flag;
	}
    cout << ans << endl;
    return 0;
}

总结

  1. 排序处理:

    • 将石头高度升序排列(a[1]到a[n]

    • 方便后续用双指针选择最高和最低的石头

  2. 双指针策略:

    * l指针初始指向最低石头(a[1]

    • h指针初始指向最高石头(a[n]
  3. 跳跃逻辑:

    • 第一跳特殊处理:从地面(0)跳到最高石头

    • 之后交替选择高低石头:

    ans += pow(a[l] - a[h], 2);
    l++; h--;  // 移动指针
    
  4. 边界处理:

    • 当石头数量为奇数时,最后一个石头会自动被处理

    • 使用 while(l <= h)确保所有石头都被访问

Logo

集算法之大成!助力oier实现梦想!

更多推荐