给定$n$个数$x_1,x_2\cdots x_n$,已知$S=\sum^{n}_{i=1}x_i(n-i)!$,求第$S$个排列
前置技能
康托展开是一个比较常用的哈希技巧,可以将一个排列$a_1,a_2\cdots a_n$映射到一个整数$k$,这个整数$k$就是这个排列在所有排列中的名次。
由于它是双射的,所以也可以从一个整数还原这个整数所对应的全排列。
假定这个排列是由$n$个数组成的,那么有从一个整数$k$映射到第$k$小的排列的方法:
将$k$写成$\sum^{n}_{i=1}x_i(n-i)!$的形式,其中对于任意$x_i$,有$0\leq x_i\leq i$。
对于第$i$次操作,选择当前没有选过的第$x_i$大的数加入排列。
进行第二步$n$次,所得的排列即为所求。
题解
注意到,题目已经完成了第一步,所以只需要完成第二步就可以了。
而数据范围$k\leq 5\times10^4$,所以要写一种高效的数据结构,支持区间第$k$小和删除一个数。
这里用权值线段树实现,由于$1\leq x_i\leq n$(这里的变量都是值上面的题意而言的),所以不用离散化。于是查询变得很简单了,但删除呢?
可以将这个数置为$0$,意思是被删除了。如果这个节点的值为$0$,那么整个子树都不复存在。
这份代码还是跑的蛮快的,$60$ms。可还是没有最优解跑的快
最后,此题卡输出格式,要像我这么写才能AC
代码
1 |
|