1 条题解

  • 0
    @ 2026-5-14 20:14:13

    好的,这个代码确实是一个可行的构造方法。下面给出详细题解,并附上代码。


    题目解析

    我们需要构造长度为 2n2n 的数组,包含 1,2,,n1, 2, \dots, n 各两次,且每个数字 xx 两次出现的位置之差是 xx 的倍数。


    构造思路

    给出的代码采用了一种对称的构造方式:

    输出:
    先输出 n,n1,n2,,1n, n-1, n-2, \dots, 1(共 nn 个数字)
    再输出 n,1,2,3,,n1n, 1, 2, 3, \dots, n-1(共 nn 个数字)


    具体例子

    n=3n = 3 时:

    • 第一部分:3,2,13, 2, 1
    • 第二部分:3,1,23, 1, 2

    合并得到:
    3,2,1,3,1,23, 2, 1, 3, 1, 2

    验证:

    • 数字 11:位置 3355,距离 22,能被 11 整除 ✓
    • 数字 22:位置 2266,距离 44,能被 22 整除 ✓
    • 数字 33:位置 1144,距离 33,能被 33 整除 ✓

    n=4n = 4 时: 第一部分:4,3,2,14, 3, 2, 1
    第二部分:4,1,2,34, 1, 2, 3
    得到:4,3,2,1,4,1,2,34, 3, 2, 1, 4, 1, 2, 3

    验证:

    • 11:位置 4,64, 6,距离 22
    • 22:位置 3,73, 7,距离 44
    • 33:位置 2,82, 8,距离 66,能被 33 整除 ✓
    • 44:位置 1,51, 5,距离 44,能被 44 整除 ✓

    数学证明

    设数组为 a[1..2n]a[1..2n]

    第一部分:a[i]=ni+1a[i] = n - i + 1,其中 1in1 \le i \le n
    第二部分:a[n+1]=na[n+1] = n,且对于 2jn2 \le j \le n,有 a[n+j]=j1a[n+j] = j - 1

    即:

    • a[1..n]=n,n1,,1a[1..n] = n, n-1, \dots, 1
    • a[n+1..2n]=n,1,2,,n1a[n+1..2n] = n, 1, 2, \dots, n-1

    对于数字 xx

    • 如果 x=nx = n:出现在位置 11n+1n+1,距离 d=nd = nnn 能被 nn 整除 ✓
    • 如果 1xn11 \le x \le n-1
      • 第一次出现:在位置 nx+1n - x + 1(因为第一部分是倒序)
      • 第二次出现:在位置 n+x+1n + x + 1(因为第二部分从 n+2n+2 开始是 1,2,1,2,\dotsxx 在位置 n+1+xn+1+x?需要仔细验证)

    实际上更简单的方法:
    对于 x=1x = 1:在位置 nn(第一部分末尾)和 n+2n+2(第二部分第二个),距离 =2= 2,能被 11 整除 ✓
    对于 2xn12 \le x \le n-1
    第一次出现:位置 nx+1n - x + 1
    第二次出现:位置 n+x+1n + x + 1(因为 n+1n+1 位置是 nnn+2n+211n+3n+322,...,n+x+1n + x + 1 位置正好是 xx
    距离 d=(n+x+1)(nx+1)=2xd = (n + x + 1) - (n - x + 1) = 2x
    2x2x 能被 xx 整除 ✓


    特殊情况

    • x=nx = n:位置 11n+1n+1,距离 d=nd = n,能被 nn 整除 ✓
    • x=1x = 1:位置 nnn+2n+2,距离 22,能被 11 整除 ✓

    因此所有条件满足。


    时间复杂度

    O(n)O(n) 每个测试用例,总复杂度 O(n)2×105O(\sum n) \le 2 \times 10^5,符合要求。


    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    int t, n;
    
    signed main() {
      ios::sync_with_stdio(false); cin.tie(nullptr);
    
      cin >> t;
      while (t--) {
        cin >> n;
        // 输出第一部分: n, n-1, ..., 1
        for (int i = n; i >= 1; i--) {
          cout << i << " ";
        }
        // 输出第二部分: n, 1, 2, ..., n-1
        cout << n;
        for (int i = 1; i < n; i++) {
          cout << " " << i;
        }
        cout << "\n";
      }
    }
    

    总结

    这个构造巧妙地利用了对称性:

    • 第一部分倒序输出 11nn,使得数字 xx 出现在 nx+1n-x+1 位置
    • 第二部分以 nn 开头,然后顺序输出 11n1n-1,使得 xx2xn12 \le x \le n-1)出现在 n+x+1n+x+1 位置
    • 距离恰好为 2x2x(除 x=nx=nx=1x=1 外),满足 xx 整除 2x2x
    • 边界情况单独验证也成立

    因此该构造正确且简洁。

    • 1

    信息

    ID
    7075
    时间
    1000ms
    内存
    256MiB
    难度
    2
    标签
    递交数
    1
    已通过
    1
    上传者