思路是 :因为选组是连续的元素,所以分组应该是一个元素的左右位置的。又因为是字典序最大的,所以 例如 8 1 9 ,1该选9,而不是8,1 、9都标记上被选择。下一次就是 2挑选周围的元素。
记录所有元素的位置(所有元素是不重复的,1-n的一个排列),然后从 1 开始遍历,查询1位置左右的哪个数大,直接输出放置并且vis标记1 和 1两边的数据。
贡献自己想出的样例
9
1 9 8 3 7 6 5 4 2
1 9 2 4 3 8 5 6 7
6
6 5 4 1 2 3
1 4 2 3 5 6
15
15 13 12 8 9 1 10 3 7 4 2 5 11 14 6
1 10 2 5 3 7 4 6 14 8 12 9 11 13 15
10
1 10 4 7 3 2 9 5 6 8
1 10 2 9 3 7 4 5 6 8
下面是鄙人的垃圾代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pp;
const int N = 300015;
int a[N];
int cnt[N]; // 记录每个 数的 位置
int vis[N]; // 标记是否被使用
int n;
int checkRight(int i) {
if ((cnt[i] - 1 < 1 || vis[a[cnt[i] - 1]]) && cnt[i] + 1 <= n && !vis[a[cnt[i] + 1]])
return true;
if (cnt[i] + 1 <= n && a[cnt[i] + 1] - i > 1 && a[cnt[i] + 1] > a[cnt[i] - 1] && !vis[a[cnt[i] + 1]])
return true;
return false;
}
int checkLeft(int i) {
if ((cnt[i] + 1 > n || vis[a[cnt[i] + 1]]) && cnt[i] - 1 >= 1 && !vis[a[cnt[i] - 1]])
return true;
if (cnt[i] - 1 >= 1 && a[cnt[i] - 1] - i > 1 && a[cnt[i] - 1] > a[cnt[i] + 1] && !vis[a[cnt[i] - 1]])
return true;
return false;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[a[i]] = i;
}
for (int i = 1; i <= n; i++) {
// cnt[i] 是i位置
if (vis[i]) {
continue;
}
if (checkLeft(i)) {
cout << i << ' ' << a[cnt[i] - 1] << ' ';
vis[i] = vis[a[cnt[i] - 1]] = 1;
} else if (checkRight(i)) {
cout << i << ' ' << a[cnt[i] + 1] << ' ';
vis[i] = vis[a[cnt[i] + 1]] = 1;
} else {
cout << i << ' ';
vis[i] = 1;
}
}
return 0;
}