题解:洛谷 P1152 欢乐的跳

【题目来源】

洛谷:P1152 欢乐的跳 - 洛谷(luogu.com.cn)

【题目描述】

一个 \(n\) 个元素的整数数组,如果数组两个连续元素之间差的绝对值包括了 \([1,n-1]\) 之间的所有整数,则称之符合“欢乐的跳”,如数组 \(\{1,4,2,3\}\) 符合“欢乐的跳”,因为差的绝对值分别为:\(3,2,1\)

给定一个数组,你的任务是判断该数组是否符合“欢乐的跳”。

【输入】

每组测试数据第一行以一个整数 \(n(1\le n\le 1000)\) 开始,接下来 \(n\) 个空格隔开的在 \([−10^8,10^8]\) 之间的整数。

【输出】

对于每组测试数据,输出一行若该数组符合“欢乐的跳”则输出 Jolly,否则输出 Not jolly

【输入样例】

4 1 4 2 3

【输出样例】

Jolly

【核心思想】

  1. 问题分析:给定一个长度为 \(n\) 的整数数组,需要判断其相邻元素差的绝对值是否恰好覆盖了 \(1\)\(n-1\) 的所有整数(顺序无关)。本质是检查这 \(n-1\) 个差值是否构成一个 \(1\)\(n-1\) 的排列。

  2. 算法选择

    • 桶标记法:创建一个大小为 \(n\) 的布尔数组 mark,初始为 false。遍历数组,计算每对相邻元素的绝对差 d = abs(a[i] - a[i+1])。若 d\(1\)\(n-1\) 范围内,将 mark[d] 设为 true。最后检查 mark[1..n-1] 是否全部为 true
    • 复杂度:时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)
  3. 关键步骤

    • 读入:读取 \(n\) 和数组 \(a[1..n]\)
    • 标记差值:循环 \(i\) 从 1 到 \(n-1\),计算 d = abs(a[i] - a[i+1]),若 1 <= d <= n-1,则 mark[d] = true
    • 检查:循环 \(i\) 从 1 到 \(n-1\),若存在 mark[i] == false,则输出 "Not jolly",否则输出 "Jolly"
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n)\)
    • 空间复杂度:\(O(n)\)
  5. 桶标记与差值覆盖

    • 核心逻辑:用布尔数组记录每个差值是否出现,最后检查是否全部出现。
    • 边界处理:差值可能超出 \(1\)\(n-1\) 范围,但题目要求覆盖该范围,因此超出范围的差值可直接忽略(不可能使条件成立)。
    • 适用场景:这类“检查一组数是否覆盖连续范围”的问题,常用桶标记法。

【解题思路】

【算法标签】

入门 #其他排序

【代码详解】

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

int main()
{
    int n, a[1005], b[1005] = {0}, mark = 1; // 定义变量:n为序列长度,a存储序列,b用于标记差值是否出现,mark用于判断是否为Jolly序列
    cin >> n; // 输入序列长度
    for (int i = 1; i <= n; i++) cin >> a[i]; // 输入序列中的元素

    // 桶排序实现
    for (int i = 1; i < n; i++) {
        int t = abs(a[i] - a[i + 1]); // 计算相邻元素的绝对差值
        if (t < 1005) b[t] = 1; // 如果差值在合理范围内,标记该差值出现过
    }

    // 检查1到n-1的所有差值是否都出现过
    for (int i = 1; i < n; i++) {
        if (b[i] == 0) { // 如果某个差值未出现
            mark = 0; // 标记为不是Jolly序列
            break; // 提前退出循环
        }
    }

    // 输出结果
    if (mark) cout << "Jolly"; // 如果所有差值都出现过,输出"Jolly"
    else cout << "Not jolly"; // 否则输出"Not jolly"

    return 0; // 程序结束
}

【运行结果】

4 1 4 2 3
Jolly
posted @ 2026-08-31 09:24  团爸讲算法  阅读(9)  评论(0)    收藏  举报