神奇的排列:算法详解及C++代码实现

问题描述

对于一个长度为 2n 的排列 p_1,p_2,...,p_{2n},定义数组 sp 中两两分组以后每个组的数字之和,即 s_i=p_{2i-1}+p_{2i},可以发现 s 的长度为 n。若 s 是一个连续严格递增数列,则我们称排列 p 为一个神奇的排列。

现在我们给定一个数字 n,请给出一个长度为 2n 可能的神奇的排列 p

输入格式

第一行一个数字 T,代表有 T 组数据。

接下来 T 行,每行一个整数 N

输出格式

如果存在满足题意的排列,请输出 YE5,并且在下一行输出一个可能的排列。如果不存在,请输出 N0

样例 #1

样例输入 #1

3
1
2
5

样例输出 #1

YE5
2 1
N0
YE5
6 3 8 2 10 1 7 5 9 4

提示

数据范围

对于 10% 的数据,N 全为偶数。
对于另外 30% 的数据,T=1
对于 60% 的数据,1≤T≤50N≤500
对于 100% 的数据,1≤T≤5001≤N≤10^5,且每组数据中,∑N≤10^5

提示

排列:长为 N 的排列指的是由 1 ~ N 组成的数列,比如 N=3 的排列有:1 2 31 3 22 1 32 3 13 1 23 2 1等共 6 个。

连续严格递增数列:对于整个数列都有第 i 个数字 a_i 和第 i+1 个数字 a_{i+1}a_{i+1}=a_i+1

算法分析

  1. 奇偶性判定: 首先,我们观察到如果 N 是奇数,则无法构造出满足题意的排列。这是因为,如果 N 是奇数,则 2N 是奇数,排列 p 的长度为奇数,无法进行两两分组。因此,当 N 为奇数时,直接输出 N0

  2. 构造神奇排列:N 为偶数时,我们可以构造一个神奇的排列。具体方法如下:

    • 初始化一个长度为 2N 的数组 p,将 12N 的数字依次填入。
    • p 中的奇数位置和偶数位置的元素进行交换。
  3. 输出结果: 构造完排列 p 后,输出 YE5 和排列 p

C++ 代码实现

#include <iostream>
#include <vector>

using namespace std;

int main() {
    int T;
    cin >> T;
    
    while (T--) {
        int N;
        cin >> N;
        
        // 如果 N 为奇数,不存在满足题意的排列
        if (N % 2 != 0) {
            cout << 'N0' << endl;
            continue;
        }
        
        // 构造一个满足题意的排列
        vector<int> p(2 * N);
        for (int i = 0; i < 2 * N; i++) {
            p[i] = i + 1;
        }
        for (int i = 0; i < 2 * N; i += 2) {
            swap(p[i], p[i + 1]);
        }
        
        // 输出排列
        cout << 'YE5' << endl;
        for (int i = 0; i < 2 * N; i++) {
            cout << p[i] << ' ';
        }
        cout << endl;
    }
    
    return 0;
}

总结

本文详细介绍了“神奇的排列”问题,并给出了一个简单的算法和 C++ 代码实现。通过分析问题本质,我们可以高效地构造满足条件的排列。

神奇的排列:算法详解及C++代码实现

原文地址: https://www.cveoy.top/t/topic/qnA0 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录