题意
定义
p为1 - n的排序
给定n和m,求使得f§ 的值最大的按照字典序排序的第m个排列
思路
关键在于使得f§值最大的排列一定是当前剩余数的最小放在排列的首部或者尾部
如果当前的剩余数的最小值不是在首或者尾,必然可以通过将该数移动到首或者尾使得f(x)的值更大
所以每次只需要判断将最小的数放在头还是尾即可
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class B2_513 {
private static int N = 55;
private int n;
private long m;
private int[] res = new int[N];
private boolean[] st = new boolean[N];
private long[] f = new long[N];
public static void main(String[] args) throws IOException {
B2_513 b2_513 = new B2_513();
b2_513.read();
b2_513.solve();
}
/**
* f(p) = sum(min(p[i] --- p[j])) i -> (1, n), j -> (i, n)
*
* example:p = {1, 2}
* i = 1, j = 1 min(p[1]) = 1
* i = 1, j = 2 min(p[1], p[2]) = 1
* i = 2, j = 2 min(p[2]) = 2
* f(p) = 4
*
* p = {1, 2, 3}
* i = 1, j = 1 min(p[1]) = 1
* i = 1, j = 2 min(p[1], p[2]) = 1
* i = 1, j = 3 min(p[1], p[2]) = 1
* i = 2, j = 2 min(p[2]) = 2
* i = 2, j = 3 min(p[2], p[3]) = 2
* i = 3, j = 3 min(p[3]) = 3
* f(p) = 10
*
*/
private void solve() {
f[0] = 1L;
f[1] = 1L;
for(int i = 2; i <= n; i++) {
f[i] = f[i - 1] * 2L;
}
dfs(1, n, n, m);
for(int i = 1; i <= n; i++) {
System.out.print(res[i] + " ");
}
System.out.println();
}
/**
*
* @param start 区间的左边
* @param end 区间的右边
* @param n 长度为n的序列
* @param m 前m个序列
*/
private void dfs(int start, int end, int n, long m) {
if(start == end) {
res[start] = n;
return ;
}
// x: 当前要填入的值
int x = n - (end - start);
if(f[n - x] >= m) {
// 添加在开头
res[start++] = x;
dfs(start, end, n, m);
} else {
// 添加在结尾
res[end--] = x;
dfs(start, end, n, m - f[n - x]);
}
}
private void read() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
n = Integer.parseInt(s[0]);
m = Long.parseLong(s[1]);
}
}