以洛谷P2425为例
Uim 成功地按照顺序将礼物送到了 N 个妹子的手里并维持她们的和谐。
现在 Uim 现在想知道,他最终选择的顺序是所有给 N 个妹子送礼顺序中,字典序第几小的。送礼顺序可以看作 1,2,⋯,N 的一个排列。
输入格式
第一行一个整数 N,表示有 N 个数。
第二行一个整数 X,表示给出的排列。
输出格式
一个整数,表示是第几小的字典序。
输入输出样例
输入 #1复制
3 231
输出 #1复制
4
说明/提示
1≤N≤9。
请注意输入的排列没有空格。
解题思路
康托展开:
康托展开式
例如求52341在{1,2,3,4,5}的生成的排列中的次序可以这样来计算:第一位是5,比5小的数有1,2,3,4四个数,所以有4X4!第二位是2,比2小的数有1一个数,所以有1X3!
第三位是3,比3小的数有1,2两个数,因为2前面已经出现过了,所以只有一个数,为1X2!
第四位是4,比4小的数有1,2,3三个数,因为2,3前面已经出现过了,所以只有一个数,为1X1!
最后一位数无论是几,比它小的数在前面肯定都出现了,所以为0X0!=0则X=4X4!+1X3! +1X2!+1X1!=105
这个X只是这个排列之前的排列数,而题目要求这个排列的位置,即52341排在第106位。
代码实现
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int a[] = new int[n];
int out = 0;
//输入排列
String str = in.next();
//将排列存入字符串中
char s[] = str.toCharArray();
//将字符数组内容传入int型数组
for (int i = 0; i < n; i++) {
a[i] = s[i] - 48;
}
//求阶乘
int fac[] = new int[20];
fac[0] = fac[1] = 1;
for (int i = 2; i < n; i++) {
fac[i] = fac[i - 1] * i;
}
//康托展开
for (int i = 0; i < a.length; i++) {
int num = 0;
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
num++;
}
}
out += num * fac[n - i - 1];
}
//注意要+1
System.out.println(out+1);
}
}