CF1741B Funny Permutation 题解

题意简述

输入一个整数 n n n,要求构造一个长度为 n n n 的排列 p p p p i ∈ [ 1 , n ] p_i \in [1,n] pi[1,n],并同时满足以下两点要求:

  • 对于排列中的每一个元素,满足在和它相邻的元素中至少有一个元素和它的值相差 1 1 1
  • 下标从 1 1 1 开始,每个下标对应的元素不能和下标相等,形式化的,对于每一个 i ∈ [ 1 , n ] i \in [1,n] i[1,n] 都必须满足 p i ≠ i p_i \neq i pi=i

如果可以构造,输出构造的排列。
如果不可以,输出 − 1 -1 1

题目分析

构造题,首先考虑第一个要求,先想到的就是按顺序排列,但是为了满足各个下标对应元素不能和下标相等,再考虑顺序移动一位,后边的补到前边,但这样就会导致最前边的元素无法满足第一个要求,所以整体向后顺序移动两位,溢出的部分补到前边。

要注意的是,顺序向后移动两位之后还要保证剩下的部分也满足第一个条件,因此这样的操作只适用于 n ≥ 4 n \geq 4 n4 的情况,那么对于 n = 1 , 2 , 3 n={1,2,3} n=1,2,3 的情况我们可以特判一下。

因此,下面代码中的 check 函数我只判断了是否满足第二个要求。

形式化的,对于 n ≥ 4 n \geq 4 n4的情况,我们在要构造的排列中先放入 n − 1 n-1 n1 n n n,然后依次放入 1 1 1 n − 2 n-2 n2 即可。

代码

#include <bits/stdc++.h>

using namespace std;

inline long long read()
{
    long long x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while (isdigit(ch))
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

bool check(vector<ll> &v)
{
    for (ll i = 0; i < v.size(); i++)
    {
        if (v[i] == i + 1)
        {
            return false;
        }
    }
    return true;
}

void solution()
{
    ll n = 0;
    n = read();

    if (n == 1)
    {
        cout << -1 << endl;
        return;
    }
    if (n == 2)
    {
        cout << 2 << ' ' << 1 << endl;
        return;
    }
    if (n == 3)
    {
        cout << -1 << endl;
        return;
    }
    vector<ll> nums;
    nums.push_back(n - 1);
    nums.push_back(n);
    for (ll i = 1; i <= n - 2; ++i)
    {
        nums.push_back(i);
    }
    if (check(nums))
    {
        for (ll i = 0; i < nums.size(); i++)
        {
            cout << nums[i] << " ";
        }
        cout << endl;
    }
    else
    {
        cout << -1 << endl;
    }
}

int main()
{
    ll T = 0;
    T = read();
    for (ll i = 0; i < T; i++)
    {
        solution();
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值