1 条题解
-
0
自动搬运
来自洛谷,原作者为

Xy_top
constructive thinking搬运于
2025-08-24 22:43:22,当前版本为作者最后更新于2022-12-04 17:30:09,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
构造题看着就头晕,其实这题还是很简单的。
首先来考虑一下不能构造的情况:
无论给你的排列怎么打乱,它的和都不变,所以我们利用等差数列公式求出它的和为: 。
题目中又说让我们用两个排列构造,那么这两个排列的数字和就是 。
由题意得这两个东西同余于 ,那么相减也同余于 。
即 整除 ,拆一下变成 ,这时需要分情况讨论。
1: 为奇数。那么 为偶数, 就是整数, 再乘以它,自然就是 的倍数啦!
2: 为偶数。那么 就是一奇一偶,相乘得到奇数,除以 后不是整数,肯定不是 的倍数啦!一定无解。
然后再来考虑 为奇数的构造。需要用到一个常用的构造方法:即右(左)移构造。
举个例子, 。那么构造的方案便是:
0 1 2 3 4 1 2 3 4 0可以发现,第二行的第 个就是第一行的第 个,下面来证明这种构造方法可以构造出 ~ :
根据同余定理,把右下角的 变成 不会影响。
然后就会发现每一列相邻两项的和都增加了 ,进一步观察发现他都是形如 的形式 。
紧接着我们发现当 时,得到的东西就是 ,全是奇数,其中最后一项取模之后得 。
当 时,取模完得 ,全是偶数。
所以这个构造方法构造出来的东西就是 ~ ,符合题意。然后就是一个桶存一下就完的事儿。
代码很简单:
#include <iostream> using namespace std; int n, a[100010], ans[2][100010]; int main() { cin >> n; if (n % 2 == 0)//没有方案的情况 { cout << -1; return 0; } for (int i = 0; i < n; i ++)//预处理 2*i+1的每一项,记录到ans数组中 { ans[0][(2 * i + 1) % n] = i; ans[1][(2 * i + 1) % n] = (i + 1) % n; } for (int i = 1; i <= n; i ++) cin >> a[i]; for (int i = 0; i < 2; i ++)//根据a数组每一项的值输出预处理好的答案。 { for (int j = 1; j <= n; j ++) cout << ans[i][a[j] ] << " "; cout << \n""; } return 0; }
- 1
信息
- ID
- 8158
- 时间
- 1500ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者