1 条题解
-
0
📝 题目大意
有 个人按编号 的顺序依次操作:若当前这个人还没有被别人叫过编号,则他叫出 的编号。求操作结束后,一次都没被别人叫过编号的所有人的编号,按升序输出。
💡 解题思路
-
题目分析:
- , 或 均可接受。
- ,意味着人不会叫自己的编号,避免了自环。
- 每个人最多操作一次,且只有"未被叫过的人"才会叫别人——这意味着操作是有条件的、单向传播的。
-
算法推导:
- 使用布尔数组
f[i]表示第 个人是否被叫过编号(初始全为false)。 - 按照 的顺序遍历:
- 若
f[i] == false(第 个人尚未被叫过),则执行操作:将f[a[i]]设为true(标记 被叫过)。 - 若
f[i] == true(第 个人已经被叫过),则跳过,不做任何事。
- 若
- 遍历结束后,再遍历一次
f数组,统计并输出所有f[i] == false的 。 - 注意:因为按 顺序遍历,输出的编号天然升序,无需额外排序。
- 使用布尔数组
-
边界与细节:
- 数组下标从 开始,开到 的大小以防越界。
y数组在标准代码中声明但未使用,属于冗余变量,不影响正确性。- 不存在全部人都被叫到的情况:题目保证 ,且至少有一人不会被叫(读者可自行验证:至少人 的初始状态决定了一定有漏网之鱼)。
⏱️ 复杂度分析
- 时间复杂度:,两次线性遍历。
- 空间复杂度:,存储 数组和 标记数组。
💻 标准代码 (C++)
#include <bits/stdc++.h> using namespace std; bool y[200005], f[200005]; // f[i]: 第i个人是否被叫过编号 int n, a[200005]; int main () { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); // 按顺序模拟每个人的操作 for (int i = 1; i <= n; i++) if (f[i] == 0) // 第i个人还没被叫过 f[a[i]] = 1; // 叫出A_i的编号,标记A_i被叫过 // 统计未被叫过的人数 int ans = 0; for (int i = 1; i <= n; i++) if (f[i] == 0) ans++; printf("%d\n", ans); // 按升序输出所有未被叫过的人的编号 for (int i = 1; i <= n; i++) if (f[i] == 0) printf("%d ", i); return 0; } -
- 1
信息
- ID
- 690
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- (无)
- 递交数
- 1
- 已通过
- 1
- 上传者