补充:刚刚留意到官方题解提到了这种方式,不过我这里描述稍微详细一点点。

看大家都是用 8 循环,其实还有一种基于对 5 取余的思路:

先考虑 nn 为 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 个排列的顺序,保证其先从小到大,不断反弹。

容易发现无论 nn 多大,只要 nn 为 5 的倍数,这个构造方式一定是可行的。

nn 模 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;
}