P1088 [NOIP2004 普及组] 火星人
// Problem: P1088 [NOIP2004 普及组] 火星人 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P1088 // Memory Limit: 125 MB // Time Limit: 1000 ms // User: Pannnn #include <bits/stdc++.h> using namespace std; /* 下一个排列总是比当前排列要大,除非该排列已经是最大的排列。 希望找到一种方法,能够找到一个大于当前序列的新序列,且变大的幅度尽可能小。 需要将左边的一个较小数与右边的一个较大数交换,以能够让当前排列变大,从而得到下一个排列。 同时要让这个较小数尽量靠右,而较大数尽可能小,当交换完成后, 较大数右边的数按照升序重新排列,可以保证新排列大于原来排列的情况下,使变大的幅度尽可能小。 以4 5 2 6 3 1为例 能找到的符合条件的一对较少数与较大数的组合为2 3,满足较小数尽可能靠右且较大数尽可能小 完成交换后,排列变为4 5 3 6 2 1,此时重排原来较小数位置右边的序列,序列变为4 5 3 1 2 6 描述算法: 对于长度为n的排列a: 首先从后向前查找第一个顺序对(i, i + 1),满足a[i] < a[i + 1],这样较小数为a[i],此时[i + 1, n)必然为降序 如果找到了顺序对,那么在区间[i + 1, n)中从后向前查找第一个元素j满足a[i] < a[j],这样较大数为a[j] 交换a[i]与a[j],此时可以证明区间[i + 1, n)必为降序,可以直接反转使其变为升序 */ void nextPermutation(vector<int> &nums) { int i = nums.size() - 2; while (i >= 0 && nums[i] >= nums[i + 1]) { --i; } if (i >= 0) { int j = nums.size() - 1; while (j >= 0 && nums[i] >= nums[j]) { --j; } swap(nums[i], nums[j]); } reverse(nums.begin() + i + 1, nums.end()); } int main() { ios::sync_with_stdio(false); cin.tie(0); int n, m; cin >> n >> m; vector<int> info(n); for (int i = 0; i < n; ++i) { cin >> info[i]; } for (int i = 0; i < m; ++i) { nextPermutation(info); } for (int i = 0; i < n; ++i) { cout << info[i] << " "; } cout << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!