P8376 [APIO2022] 排列 的一个简短做法

· · 题解

一句话题意

朴素做法

考虑从小到大加数。

显然(记当前递增子序列数为 ans):

则我们得到了一个简单的构造方法:对 K 进行二进制处理即可。

## 优化做法 **注意到 $1.5 \times 60 = 90$(qwq)**。 而 $\times 2$ 的操作是**满的**,不可优化。 这提示我们对 $+1$ 操作进行优化,尝试**合并** $+1$ 操作(一次处理多个二进制 $1$)。 显然 $+1$ 操作每次将**最大**的数添加至最前,所以是**单调递减**的(如图中 **O**)。 | O | | | | | | :---: | :---: | :---: | :---: | :---: | | | | | | * | | | **O** | | | | | | | | * | | | | | **O** | | | 而**单调递减**正是 $ans$ 增长较慢的原因(每次只 $+1$)。 考虑将新的数插到第三位(如图中 **X**,注意数是**从小到大**插入的)。 | | | **X** | | | | | :---: | :---: | :---: | :---: | :---: | :---: | | **O** | | | | | | | | | | | | * | | | **O** | | | | | | | | | | * | | | | | | **O** | | | 可使 $ans \to ans + 3$(即一次处理两个二进制 $1$)。 ### 综上 记 $K$ 为目标数,则有以下操作: 1. 当 $K \bmod 2 = 0$ 时,将数加到最后,$K \to \frac{K}{2}$。 2. 当 $K \bmod 4 = 1$ 时,先将数放到最前,$K \to K - 1$,再做两次 $1$ 操作。 3. 当 $K \bmod 4 = 3$ 时,先将数放到第三位,$K \to K - 3$,再做两次 $1$ 操作。 4. 注意到 $3$ 操作前须有至少 $2$ 个 $2$ 操作,则可在 $K \le 4$ 时暴力进行 $2$ 操作以保证。 则此时每加 $3$ 个数后 $K$ 至少除以 $4$,$len_{max} = 1.5 \times \log{K} \approx 90$。 ## ACcode ```cpp #include<bits/stdc++.h> using namespace std; vector<int > ans; int n; void work(long long x) { if (x <= 4) { while (--x) ans.insert(ans.begin(), n++); return; } //x<=4时暴力+1以保证+1操作数>=2 if (x % 2 == 0) work(x >> 1), ans.push_back(n++); else if (x % 4 == 1) work(x - 1), ans.insert(ans.begin(), n++); else if (x % 4 == 3) work(x - 3), ans.insert(ans.begin() + 2, n++); } vector<int > construct_permutation(long long k) { ans.resize(n = 0); work(k); return ans; } ``` 感谢审核,辛苦 : ) 。