UVA 11525

UVA 11525
(一种通过康托展开求排列的方法)
Problem
  给定一个1-K的排列的康托展开形式,即S 1 *(K-1)! + S 2 *(K-2)! + S 3 *(K-3)! +......+ S K (K-K)!;输出排列。

Limits
Time Limit(ms); 3000
Memory Limit(MB): No Limit
K: [1, 50000]
Si: [0, K - i]

Solution
  根据康托展开的定义,可以看出,Si 表示的是当前比排列 i 位置的数小且没有在[1, i-1] 位置出现过的数的个数(具体可以参照百度百科或wiki)。问题则可以转化为:起初K个人排队,1,2,3,...,K;每次给定一个S,找到当前排第S位的人,让其出列,再如此循环,要求每次都准确找到排第S位的人是哪一个人。注意每一次S都可能不一样,出列后的人不再属于当前队伍。怎么做?用线段树动态查找就可以实现。

More
  定义线段树每个结点表示不同的区间,根结点表示总区间,将区间二分成左孩子和右孩子,表示左半区间和右半区间,每个结点有一个域值,表示当前区间中含有的人数。起初,叶子结点域值为1,表示含有1个人,父亲域值等于左右孩子域值之和。Si +1实则表示当前是第S个人,用线段树动态查找,若左孩子域值大于等于S,则往左孩子查找,S不变;否则,往右孩子查找,S=S-左孩子域值。直到查到叶子结点为止,返回区间左端点(或右端点)。
  用二分+线段树也可以实现,但复杂度为O(K*logK*logK)。

Complexity
Time Complexity: O(K*logK)
Memory Complexity: O(4*K)

Source
UVA 11525
百度百科关于康托展开的介绍

Code
UVA 11525 From My Github


你可能感兴趣的:(数据结构,线段树,排列,康托展开)