题解:洛谷 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
【核心思想】
-
问题分析:给定一个长度为 \(n\) 的整数数组,需要判断其相邻元素差的绝对值是否恰好覆盖了 \(1\) 到 \(n-1\) 的所有整数(顺序无关)。本质是检查这 \(n-1\) 个差值是否构成一个 \(1\) 到 \(n-1\) 的排列。
-
算法选择:
- 桶标记法:创建一个大小为 \(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)\)。
- 桶标记法:创建一个大小为 \(n\) 的布尔数组
-
关键步骤:
- 读入:读取 \(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"。
-
时间/空间复杂度:
- 时间复杂度:\(O(n)\)。
- 空间复杂度:\(O(n)\)。
-
桶标记与差值覆盖:
- 核心逻辑:用布尔数组记录每个差值是否出现,最后检查是否全部出现。
- 边界处理:差值可能超出 \(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
浙公网安备 33010602011771号