E. Almost Sorted
我们定义 almost sorted 数组为,ai+1≥ai−1a_{i + 1} \geq a_i - 1ai+1≥ai−1,也就是说,
先写几项出来看看:
n = 1
1
n = 2
1 2
2 1
n = 3
1 2 3
1 3 2
2 1 3
3 2 1
容易发现一定是,形如x,x−1,x−2,…,1,…x, x - 1, x - 2, \dots, 1, \dotsx,x−1,x−2,…,1,…,这样的,也就是前缀是一连串的下降的数字,
假设数字长度为nnn,前缀下降长度为mmm,则这样的方案就是长度为n−mn - mn−m的排类的方案了,
假设f(n)f(n)f(n)表示长度为nnn的方案, 则f(n)=∑i=0n−1f(i)f(n) = \sum\limits_{i = 0} ^{n - 1} f(i)f(n)=i=0∑n−1f(i),f(0)=1f(0) = 1f(0)=1,
到这里,其实就是解决若干个子问题了,所以就可以递归,或者 while 去构造了。
#include <bits/stdc++.h>using namespace std;int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);map<int, long long> mp;mp[0] = 1, mp[1] = 1, mp[2] = 2;for (int i = 3; i <= 62; i++) {mp[i] = mp[i - 1] * 2;}int T, n, cur;scanf("%d", &T);while (T--) {long long k, temp;scanf("%d %lld\n", &n, &k);temp = k - 1;int num = 0;while (temp) {num++;temp >>= 1;}num++;if (num > n) {puts("-1");continue;}for (int i = 1; i <= n - num; i++) {printf("%d ", i);}cur = n - num + 1;while (k) {if (k == (1ll << num - 1)) {for (int i = n; i >= n - num + 1; i--) {printf("%d ", i);}break;}long long sum = 0;while (num && sum + mp[num - 1] < k) {num--;sum += mp[num];}k -= sum;num--;for (int i = n - num; i >= cur; i--) {printf("%d ", i);}cur = n - num + 1;}puts("");}return 0;
}