【牛客 NC253455】小红走排列 题解(链表+位集合+贪心算法)

2024-02-19 06:20

本文主要是介绍【牛客 NC253455】小红走排列 题解(链表+位集合+贪心算法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

对于一个排列,小红定义该排列的总消耗为:1走到2,2走到3,……,最终从 n − 1 n-1 n1走到 n n n所需的最少的总步数。其中,每一步可以向左走一步,也可以向右走一步。

现在,小红只记得排列的大小 n n n和走的步数 k k k,但不记得排列的构造情况了。请你帮小红还原整个排列。

输入描述

两个正整数 n n n k k k,用空格隔开。

满足条件: 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105 n − 1 ≤ k ≤ n ∗ ( n − 1 ) / 2 n-1 \leq k \leq n*(n-1)/2 n1kn(n1)/2

输出描述

如果无解,请输出-1。

否则输出构造的排列。有多解时输出任意即可。

示例

示例1

输入:

3 2

输出:

1 2 3

说明:

小红从1号开始,向右跳两步即可先跳到2,再跳到3。输出[3,2,1]这个排列也符合要求。

示例2

输入:

4 6

输出:

1 3 4 2

思路

使用bitset来存储标记,使用list来存储结果排列。

从输入中读取 n n n k k k,然后计算 j j j j j j是用 k k k减去 n − 1 n-1 n1的结果,表示除了从每个数字到下一个数字至少需要的步数(即1步)之外,还剩下多少步可以用于调整排列的顺序。

然后对从 n − 2 n-2 n2 1 1 1的每个 i i i进行循环,如果剩余的步数 j j j大于等于 i i i,就将 j j j减去 i i i,并将 v i s [ i + 2 ] vis[i+2] vis[i+2]标记为已访问。通过贪心算法,尽可能地使用剩余的步数来改变排列的顺序。

定义一个布尔变量dir,用于控制新的元素是添加到排列的前面还是后面。对于从 1 1 1 n n n的每个 i i i,如果 v i s [ i ] vis[i] vis[i]被标记为已访问,就反转dir。然后根据dir的值,将 i i i添加到排列的前面或后面。

最后,输出排列中的每个元素。这个排列就是问题的一个解。如果有多个解,输出任意一个即可。

输出描述中提到,如果无解,请输出-1。如果给定的步数 k 大于 n ∗ ( n − 1 ) / 2 n*(n-1)/2 n(n1)/2 或小于 n − 1 n-1 n1,那么就无法找到一个排列使得总消耗等于 k,即这个问题无解。但是输入描述中,给定 k 的范围为 n − 1 ≤ k ≤ n ∗ ( n − 1 ) / 2 n-1 \leq k \leq n*(n-1)/2 n1kn(n1)/2,所以无解的情况实际上是不会出现的,不需要特别考虑无解。


AC代码

#include <algorithm>
#include <bitset>
#include <iostream>
#include <list>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;const int N = 1e5 + 7;ll n, k;
list<int> li;
bitset<N> vis;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);li.clear();vis.reset();cin >> n >> k;ll j = k - (n - 1);for (int i = n - 2; i > 0; i--) {if (j >= i) {j -= i;vis[i + 2] = 1;}}bool dir = 0;for (int i = 1; i <= n; i++) {if (vis[i]) {dir ^= 1;}if (dir) {li.push_front(i);} else {li.push_back(i);}}for (const auto i : li) {cout << i << " ";}cout << endl;return 0;
}

这篇关于【牛客 NC253455】小红走排列 题解(链表+位集合+贪心算法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/723762

相关文章

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

Linux链表操作方式

《Linux链表操作方式》:本文主要介绍Linux链表操作方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、链表基础概念与内核链表优势二、内核链表结构与宏解析三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势六、典型应用场景七、调试技巧与

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Springboot实现推荐系统的协同过滤算法

《Springboot实现推荐系统的协同过滤算法》协同过滤算法是一种在推荐系统中广泛使用的算法,用于预测用户对物品(如商品、电影、音乐等)的偏好,从而实现个性化推荐,下面给大家介绍Springboot... 目录前言基本原理 算法分类 计算方法应用场景 代码实现 前言协同过滤算法(Collaborativ

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n