P1152 欢乐的跳

6 阅读2分钟

这是一个考察数组模拟(桶思想)和差值处理的经典题目。

解题思路

  1. 目标分析:

    我们需要验证 nn 个数的序列中,相邻两个数的差的绝对值,是否完整地覆盖了 11n1n-1 之间的每一个整数。

  2. 核心步骤

    • 计算差值:遍历数组,算出相邻两数的绝对差 diff = abs(a[i] - a[i+1])
    • 标记出现:我们需要记录哪些差值已经出现过。由于差值的范围是确定的(1n11 \sim n-1),我们可以开一个布尔数组(或 vector<bool>)作为“桶”来标记。
      • 例如:如果算出差值是 3,就把 marked[3] 设为 true
    • 检查完整性:最后遍历一遍 11n1n-1,只要发现有一个数字没被标记过,就说明不符合要求,输出 Not jolly。如果全都出现过,则输出 Jolly

C++ 参考代码

#include <iostream>
#include <vector>
#include <cmath> // 用于 abs() 函数

using namespace std;

int main() {
    int n;
    cin >> n;

    // 读入数组
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }

    // 标记数组,用于记录差值是否出现过
    // 大小设为 n 即可,下标范围 0 ~ n-1
    vector<bool> has_diff(n, false);

    // 计算相邻差值
    for (int i = 0; i < n - 1; ++i) {
        // 计算绝对值
        int diff = abs(a[i] - a[i+1]);

        // 我们只关心范围在 1 到 n-1 之间的差值
        if (diff >= 1 && diff < n) {
            has_diff[diff] = true;
        }
    }

    // 检查 1 到 n-1 是否都存在
    for (int i = 1; i < n; ++i) {
        if (!has_diff[i]) {
            cout << "Not jolly" << endl;
            return 0; // 一旦发现缺失,直接结束程序
        }
    }

    // 如果循环顺利结束,说明都存在
    cout << "Jolly" << endl;

    return 0;
}

代码解析要点

  • abs() 函数:位于 <cmath> 头文件中,用于计算绝对值。
  • 边界判断:在标记 has_diff 时,必须先判断 diff 是否在合法范围 [1,n1][1, n-1] 内。如果差值很大(比如 n=5n=5,差值为 100100),直接忽略即可,因为它对“覆盖 141 \sim 4”没有帮助,反而直接访问数组会导致越界错误(RE)。
  • n=1n=1 的情况:虽然题目逻辑上通常指 n2n \ge 2,但如果输入 n=1n=1,代码中的两个循环都不会执行(范围不成立),最终直接输出 Jolly,这也符合题目的隐含定义(空集覆盖空集)。