NOIP2004P4 火星人 题解
(题目描述略)
本题题意为求给定长度为 n 的数列的后第 m 个全排列(字典序)。
对于一个给定的数列 a[0 .. n-1],求其下一个字典序的全排列算法如下:
- 从右向左查询最大的下标 i (0 ≤ i ≤ n-1) 使得 a[i] < a[i+1];
- 从左向右查询最小的元素 a[j] (i+1 ≤ j ≤ n-1) 使得 a[i] < a[j];
- 交换 a[i] 和 a[j];
- 逆置翻转 a[i+1 .. n-1]。
算法分析:我们可以发现,第一步求出的 i 下标表示 a[i+1 .. n-1] 是一个长度为 n-i-1 的最后一个全排列,且 a[i .. n-1] 是一个长度为 n-i 的非末全排列。这样,我们可以不改变 a[0 .. i-1],而对 a[i .. n-1] 求其下一个全排列。
因为以 a[i] 为起始的全排列已经完成,所以其构造方法必然是将 a[i] 换成 a[i+1 .. n-1] 中比 a[i] 大的且最小的数,即为 a[j]。下面我们来比较 a[i] 和 a[j+1] 之间的大小关系。显然,a[i] ≠ a[j+1]。假设 a[i] < a[j+1],我们有 a[i] < a[j+1] < a[j],与条件 a[j] 为所有大于 a[i] 的数中最小的数矛盾。故 a[i] > a[j+1]。
由于 a[i+1] > a[i+2] > .. > a[j] > a[j+1] > .. > a[n-1],且 a[i] < a[j],a[i] > a[j+1],故 a[i+1] > a[i+2] > .. > a[j] > a[i] > a[j+1] > .. > a[n-1]。当交换 a[i] 和 a[j] 后,a[i+1 .. n-1] 必然严格降序排列。显然,交换 a[i] 和 a[j] 前 a[i .. n-1] 的下一个排列为交换 a[i] 和 a[j] 后以 a[i] 为起始的第一个排列。于是,将 a[i+1 .. n-1] 逆置翻转,得到原数列的下一个全排列。
特别的,当 i 不存在时,原数列即为以 n 为长度的全排列的末排列。当然,在本题中无此类情况。
代码如下:
#include"iostream"
#include"stdio.h"
using namespace std;
int number[10005];
int main()
{freopen("martian.in","r",stdin);freopen("martian.out","w",stdout);int i,j,m,n,temporary;cin>>n>>m;for(i=0;i<n;i++)scanf("%d",&number[i]);while(m--){for(i=n-2;number[i]>number[i+1];i--);j=i+1;for(int k=i+2;k<n;k++)if((number[i]<number[k])&&(number[j]>number[k]))j=k;temporary=number[i];number[i]=number[j];number[j]=temporary;for(int left=i+1,right=n-1;left<right;left++,right--)temporary=number[left],number[left]=number[right],number[right]=temporary;}for(i=0;i<n;i++)printf("%d ",number[i]);return 0;
}
对于本题,我们还可以调用库函数直接出解。next_permutation 是一个定义在 algorithm 库里的函数,功能是求一个一维整型数组的下一个全排列,原理同上,用法见下。
代码如下:
#include"algorithm"
#include"iostream"
#include"stdio.h"
using namespace std;
int a[10005];
int main()
{freopen("martian.in","r",stdin);freopen("martian.out","w",stdout);int m,n;cin>>n>>m;for(int i=0;i<n;i++)scanf("%d",&a[i]);while(m--)next_permutation(a,a+n);for(int i=0;i<n;i++)printf("%d ",a[i]);return 0;
}
时间复杂度:O(nm)
NOIP2004P4 火星人 题解相关推荐
- excel行列突出显示_在Excel中突出显示即将到来的日期
excel行列突出显示 Do you use Excel to keep track of upcoming payments, or other dates? To make that list m ...
- 火星人(洛谷P1088题题解,C++语言描述)
题目要求 题目链接 分析 STL有一个函数next_permutation(),直接给出下一个序列. 想自己做的话,建议学习康托展开. AC代码 #include <iostream> # ...
- BZOJ1014: [JSOI2008]火星人prefix
BZOJ1014: [JSOI2008]火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这 ...
- [JSOI2008]火星人 hash+splay
题目描述: 现在,火星人定义了一个函数 LCQ(x, y)LCQ(x,y),表示:该字符串中第 xx 个字符开始的字串,与该字符串中第 yy 个字符开始的字串,两个字串的公共前缀的长度.比方说,LCQ ...
- 一些noip模拟题一句话题解
Problem A: 序列 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 12 Solved: 9 [Submit][Status][Web Bo ...
- 河工计院ACM2022寒假培训题单以及超详细题解
目录 货仓选址 校门外的树 奖学金 蛇形矩阵 找硬币 回文平方 品种邻近 平方矩阵 II 十三号星期五 阶乘 干草堆 火星人 整数集合划分 最大的和 剪绳子 分巧克力 a^b 数独检查 ISBN号码 ...
- 洛谷P1088.火星人【模拟/搜索/康托展开】
洛谷P1088.火星人[模拟/搜索/康托展开] 题干 题目描述 输入格式 输出格式 输入输出样例 说明/提示 题意 思路一--模拟 分析 上代码 思路二--搜索 分析 上代码 思路三--变进制数与康托 ...
- 火星人-洛谷 1088
题目描述人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学家 ...
- 题目:洛谷1088 火星人(排列组合问题)
题目描述: 人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科 ...
最新文章
- ITSM四大管理工具的比较
- 【周鸿祎:当下AI技术并不完善,存四大“冰点”】
- 百度地图api改变覆盖物背景实例及css颜色值简介
- json对象和json字符串之间的转化
- 使用poi写入doc文档中文档打不开_基于NodeJS和浏览器的PDF文档引擎——PDFKit
- C++中const迭代器 和 const_iterator的区别
- 基于MaxCompute+PAI的用户增长方案实践
- SpringBoot之AOP详解
- 如何卸载非linux系统分区,如何卸载Linux系统分区?卸载Linux系统分区的方法-站长资讯中心...
- 2021-2022元宇宙报告:化身与智造,元宇宙座标解析
- 马克思知识点总结(二)
- 20春学期《计算机应用基础》在线作业2,东大20春学期《计算机应用基础》在线平时作业2答案...
- 递归算法在生成树型结构中,几乎完全属于无稽的算法
- 一天一个小技巧(1)——CSDN编辑器中文字颜色、尺寸、类型修改
- 文件或目录损坏且无法读取怎么办?数据恢复用这招
- 2017第九届广州国际园林机械与园艺工具展会刊(参展商名录)
- Code For Better 谷歌开发者之声 ——Tensorflow与深度学习
- Linux开放80端口
- 小程序智能聊天机器人(二)
- 计算机时代的英语阅读,利用微信平台提升英语类专业学生课外阅读能力的实 践意义...