给定一个长度为 2 n 2n 2n 的数组,问使得这个数组的字典序最小,最后的数组是什么样。
每次操作可以选择一个 index ,删除 a [ i n d e x ] a[index] a[index] 和 a [ i n d e x + n ] a[index+n] a[index+n] ,但是数组最后不能为空
因为最终剩余的部分以原本的前 n n n 个数的大小为准,所以这里以前 n n n 个数作一个单调非递减的序列 v e c vec vec , v e c vec vec 是存储每个数的索引
这里令后 n n n 个为 b b b ,即 b [ i ] = a [ i + n ] b[i]=a[i+n] b[i]=a[i+n]
如果 b [ v e c [ 0 ] ] ≤ a [ v e c [ 0 ] ] b[vec[0]]\leq a[vec[0]] b[vec[0]]≤a[vec[0]] ,那么这是最短的,即为答案。
否则
b
[
v
e
c
[
0
]
]
>
a
[
v
e
c
[
0
]
]
b[vec[0]]>a[vec[0]]
b[vec[0]]>a[vec[0]] ,那么我们需要分类讨论:
此时已经选了
i
i
i 个
v
e
c
vec
vec 中的元素,那么必然是前
i
i
i 个,接下来继续考虑第
i
+
1
i+1
i+1 个即
v
e
c
[
i
]
vec[i]
vec[i]
时间复杂度: O ( n ) O(n) O(n)
#include
using namespace std;
void solve() {
int n;
cin >> n;
vector<int> a(n);
vector<int> b(n);
for (int i = 0; i < n; ++i) cin >> a[i];
for (int i = 0; i < n; ++i) cin >> b[i];
vector<int> vec;
for (int i = 0; i < n; ++i) {
while (!vec.empty() && a[i] < a[vec.back()]) vec.pop_back();
vec.push_back(i);
}
// vec 是一个递增的
int len = int(vec.size());
int cur = 0;
int minv = b[vec[0]];
int state = 0;
for (int i = 0; i < len && a[vec[i]] == a[vec[0]]; ++i) {
minv = min(minv, b[vec[i]]);
cur = i;
if (i > 0) {
if (state == 0) {
if (b[vec[i]] > b[vec[i - 1]]) state = 1;
else if (b[vec[i]] < b[vec[i - 1]]) state = -1;
}
}
}
if (minv <= a[vec[0]]) {
cout << a[vec[0]] << " " << minv;
return;
}
for (int i = cur + 1; i < len; ++i) {
if (a[vec[i]] < b[vec[0]] || (a[vec[i]] == b[vec[0]] && state == 1)) {
int j = i;
while (j < len && a[vec[j]] == a[vec[i]]) {
if (state == 0) {
if (b[vec[j]] > b[vec[j - 1]]) state = 1;
else if (b[vec[j]] < b[vec[j - 1]]) state = -1;
}
j += 1;
}
cur = j - 1;
i = j - 1;
} else {
break;
}
}
for (int i = 0; i <= cur; ++i) cout << a[vec[i]] << " ";
for (int i = 0; i <= cur; ++i) cout << b[vec[i]] << " \n"[i == cur];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1;
// cin >> T;
while (T--) {
solve();
}
return 0;
}