1 条题解
-
0
C. Combination Lock 详细题解
一、问题重述
构造一个长度为 的排列 (数字 到 各出现一次),使得对于每一个循环移位,恰好有一个位置 满足该位置上的值等于其位置编号。
输出任意一个满足条件的排列;如果不存在,输出 。
二、核心推导
2.1 数学转化
将排列下标从 开始考虑(),设 为下标 处的值()。
一个循环移位相当于将数组向右移动 位()。原下标 在移位后的新下标为 。
“恰好有一个固定点”意味着:对于每个 ,存在唯一的 使得:
记 ,则条件为:
整理得:
对于固定的 ,由 唯一确定。因此映射 是双射。故 必须恰好是 。
2.2 必要条件
对全体 求和:
$$\sum_{i=0}^{n-1} (q_i - i) \equiv \sum_{k=0}^{n-1} k \pmod{n} $$左边:
$$\sum q_i - \sum i = \frac{n(n-1)}{2} - \frac{n(n-1)}{2} = 0 $$右边:
因此:
即 ,等价于 为整数?不对,检查:
当且仅当 是奇数。因为 , 整除该项当且仅当 是整数,即 为奇数。
结论:当 为偶数时无解,输出 。
三、构造方案( 为奇数)
当 为奇数时,一个简单的构造是:
即降序排列。
验证:将 转换为 -基 ?实际 ( 从 开始),。计算 :
当 取 时, 遍历所有 个不同值(因为 奇数, 可逆)。因此每个 恰好对应一个 。
四、标程代码
#include <iostream> using namespace std; void solve() { int n; cin >> n; if (n % 2 == 0) { cout << -1 << endl; return; } for (int i = n; i > 0; i--) { cout << i << " \n"[i == 1]; } } int main() { int t; cin >> t; while (t--) { solve(); } return 0; }
五、示例验证
示例 1:(偶数)
输出
-1✅示例 2:
输出
5 4 3 2 1,检查各循环移位(‑基):- 移位 0:
4 3 2 1 0→ 固定点:下标 4(值 0)? 等,需要仔细。 实际上原例输出是4 1 3 5 2,说明不唯一。本题只要任意解,降序也可行。
示例 3:
输出
3 2 1,循环移位:3 2 1:固定点?值=位置?3在位置 1 不等,2在位置 2 等,1在位置 3 不等 → 1 个固定点1 3 2:1=位置1,3≠2,2=位置3?位置3 值是2 → 1 个固定点2 1 3:2≠1,1≠2,3=3 → 1 个固定点 ✅
六、复杂度分析
- 每个测试用例
- 总 不超过 ,,可通过
七、总结
条件 结论 为偶数 无解,输出 为奇数 有解,降序排列 是一种构造 核心思想:利用模 的线性同余性质,推导出 必须为奇数,并给出简单构造。
- 移位 0:
- 1
信息
- ID
- 7261
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者