补充:刚刚留意到官方题解提到了这种方式,不过我这里描述稍微详细一点点。
看大家都是用 8 循环,其实还有一种基于对 5 取余的思路:
先考虑 为 5 的倍数的情况,例如对于 20,我们拆成五组:
- 1, 6, 11, 16
- 2, 7, 12, 17
- 3, 8, 13, 18
- 4, 9, 14, 19
- 5, 10, 15, 20
排列内部相减得到 5,只需要排列连接处也能满足题意即可。
尝试把这 5 个排列组合,使之满足题意,变成:
- [5, 10, 15, 20], [17, 12, 7, 2], [1, 6, 11, 16], [19, 14, 9, 4], [3, 8, 13, 18]
我们用 {5, 2, 1, 4, 3}
描述这个规律,表示取上述 5 个排列的顺序,保证其先从小到大,不断反弹。
容易发现无论 多大,只要 为 5 的倍数,这个构造方式一定是可行的。
在 模 5 得到其他数的时候,也可以找到这样的规律,这是我们队打的表:
int cht[5][5] = {{5, 2, 1, 4, 3},
{5, 2, 1, 3, 4},
{1, 3, 4, 2, 5},
{5, 3, 4, 2, 1},
{1, 4, 3, 5, 2}};
根据这种思路可以快速写出代码:
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
int n;
std::cin >> n;
int s = n % 5;
for (int i = 0; i < 5; i++) {
if (i % 2 == 0) {
for (int j = cht[s][i]; j <= n; j += 5) {
std::cout << j << ' ';
}
} else {
for (int j = cht[s][i] + (n / 5 + 3) * 5; j > 0; j -= 5) {
if (j <= n) {
std::cout << j << ' ';
}
}
}
}
std::cout << '\n';
}
return 0;
}