Ignatius and the Princess II
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7645 Accepted Submission(s): 4524
"Now I will show you the first problem." feng5166 says, "Given a sequence of number 1 to N, we define that 1,2,3...N-1,N is the smallest sequence among all the sequence which can be composed with number 1 to N(each number can be and should be use only once in this problem). So it's easy to see the second smallest sequence is 1,2,3...N,N-1. Now I will give you two numbers, N and M. You should tell me the Mth smallest sequence which is composed with number 1 to N. It's easy, isn't is? Hahahahaha......"
Can you help Ignatius to solve this problem?
6 4 11 8
1 2 3 5 6 4 1 2 3 4 5 6 7 9 8 11 10
大致题意:
给定一个含有N个元素的数列:1,2,3,4,......N,输出它经过M次变换后的数列。每次变换都是把数列变成仅比当前数列大的数列,比如 12345 变换一次就是 12354 。12345 与 12435 之间隔着 12354 ,所以 12435 不是变换一次后所得的答案。
大体思路:
网上搜了一下感觉我的思路似乎比较小众,遂决定写一篇题解分享一下。
1)首先讨论一下变换的过程,对于一个数列,我们要把它变成下一个数列,首先考虑把它末两位交换,这样就能得到下一个排列。但是如果末两位已经是降序了,就要移动倒数第三位(如1243,如果把末两位互换,得到的1234比1243还小,是它的上一个排列)。倒数第三位成最后两位中比原倒数第三位大的一个数。如果两个数都比原倒数第三位大,则选其中的较小者。然后继续变换后两位,变换到后三位为严格的降序之后,再变换倒数第四位,以此类推。由于原始数列是严格升序的12345...N,所以变换总是遍历了后面数位的全排列之后,再试图更改靠前的数位。
如:12345->12354->12435->12453->12534->12543->13245......根据这一点创建一个数组T={1,1,2,6,24,120,720,5040},以此确定,要变换第i位,M需要有多大。
2)对于给定的M,将其与T中的元素从后往前依次比较,以找出恰好比M小的那个元素,它的位号就是要变换的数位(倒数第i位)。由于原数列是严格升序的,所以 倒数第i位 和 倒数i-1 位交换后,最后 i-1 位是严格升序的,此时的排列是变换 倒数第i位 后最小的排列。
3)M=M-T[i],重复上述 2) ,知道M==1,表示目标排列是当前排列基础上的第一种排列,即当前排列就是目标排列,任务达成。输出排列即可。
以上是第一版思路,但思路有点缺陷导致了一次WA。
如果M=5,第一次变换交换倒数第二位和倒数第三位,M=M-2。进行第二次变换,仍是交换倒数第二位和倒数第三位,刚刚换好的又给换回来了,相当于啥也没干2333。
这一点小bug却也不难解决。只需要在第一版思路的基础上加加一个变量cnt,记录交换数位的重复次数。还是M=5的例子。第一次交换A[N-i] 和 A[N-i+1],第二次则需要交换A[N-i]和A[N-i+1+1]。其中A[N-i+1+1]里的第二个1就是cnt,我们也可以把第一次交换时的A[N-i+1]写成A[N-i+1+0],那就可以一般化为 交换 A[N-i]和A[N-i+1+cnt]。加上一个cnt,小小的bug便迎刃而解。
总是心里有但是说不出来,这篇题解我自己看了也是一脸蒙圈2333.。。。