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

题目描述

对于一个排列,小红定义该排列的总消耗为:1走到2,2走到3,......,最终从 n − 1 n-1 n−1走到 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 1≤n≤105 和 n − 1 ≤ k ≤ n ∗ ( n − 1 ) / 2 n-1 \leq k \leq n*(n-1)/2 n−1≤k≤n∗(n−1)/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 n−1的结果,表示除了从每个数字到下一个数字至少需要的步数(即1步)之外,还剩下多少步可以用于调整排列的顺序。

然后对从 n − 2 n-2 n−2到 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∗(n−1)/2 或小于 n − 1 n-1 n−1,那么就无法找到一个排列使得总消耗等于 k,即这个问题无解。但是输入描述中,给定 k 的范围为 n − 1 ≤ k ≤ n ∗ ( n − 1 ) / 2 n-1 \leq k \leq n*(n-1)/2 n−1≤k≤n∗(n−1)/2,所以无解的情况实际上是不会出现的,不需要特别考虑无解。


AC代码

cpp 复制代码
#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;
}
相关推荐
可编程芯片开发6 分钟前
基于PSO粒子群优化PI控制器的无刷直流电机最优控制系统simulink建模与仿真
人工智能·算法·simulink·pso·pi控制器·pso-pi
cpp_25016 分钟前
P8448 [LSOT-1] 暴龙的土豆
数据结构·c++·算法·题解·洛谷
lcj25117 分钟前
深入理解指针(4):qsort 函数 & 通过冒泡排序实现
c语言·数据结构·算法
fie88898 分钟前
基于MATLAB的转子动力学建模与仿真实现(含碰摩、不平衡激励)
开发语言·算法·matlab
唐梓航-求职中15 分钟前
编程大师-技术-算法-leetcode-1472. 设计浏览器历史记录
算法·leetcode
_OP_CHEN18 分钟前
【算法基础篇】(五十八)线性代数之高斯消元法从原理到实战:手撕模板 + 洛谷真题全解
线性代数·算法·蓝桥杯·c/c++·线性方程组·acm/icpc·高斯消元法
唐梓航-求职中26 分钟前
编程大师-技术-算法-leetcode-355. 设计推特
算法·leetcode·面试
少许极端33 分钟前
算法奇妙屋(二十八)-递归、回溯与剪枝的综合问题 1
java·算法·深度优先·剪枝·回溯·递归
仰泳的熊猫34 分钟前
题目1453:蓝桥杯历届试题-翻硬币
数据结构·c++·算法·蓝桥杯
唐梓航-求职中34 分钟前
技术-算法-leetcode-1606. 找到处理最多请求的服务器(易懂版)
服务器·算法·leetcode