Neutral Tonality—CF1894D
给定一个由 n n n个整数组成的数组 a a a,以及一个由 m m m个整数组成的数组 b b b。
LIS ( c ) \text{LIS}(c) LIS(c)表示数组 c c c的最长递增子序列的长度。例如, LIS ( [ 2 , 1 ‾ , 1 , 3 ‾ ] ) \text{LIS}([2, \underline{1}, 1, \underline{3}]) LIS([2,1,1,3]) = 2 2 2, LIS ( [ 1 ‾ , 7 ‾ , 9 ‾ ] ) \text{LIS}([\underline{1}, \underline{7}, \underline{9}]) LIS([1,7,9]) = 3 3 3, LIS ( [ 3 , 1 ‾ , 2 ‾ , 4 ‾ ] ) \text{LIS}([3, \underline{1}, \underline{2}, \underline{4}]) LIS([3,1,2,4]) = 3 3 3。
你需要将数字 b 1 , b 2 , … , b m b_1, b_2, \ldots, b_m b1,b2,…,bm插入到数组 a a a中的任意位置,任意顺序。令结果数组为 c 1 , c 2 , … , c n + m c_1, c_2, \ldots, c_{n+m} c1,c2,…,cn+m。你需要选择插入位置以最小化 LIS ( c ) \text{LIS}(c) LIS(c)。
也就是说,你需要找到一个数组 c 1 , c 2 , … , c n + m c_1, c_2, \ldots, c_{n+m} c1,c2,…,cn+m,同时满足以下条件:
输入
每个测试包含多个测试用例。第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 ) (1 \leq t \leq 10^4) (1≤t≤104),表示测试用例的数量。接下来是测试用例的描述。
每个测试用例的第一行包含两个整数 n , m n, m n,m ( 1 ≤ n ≤ 2 ⋅ 1 0 5 , 1 ≤ m ≤ 2 ⋅ 1 0 5 ) (1 \leq n \leq 2 \cdot 10^5, 1 \leq m \leq 2 \cdot 10^5) (1≤n≤2⋅105,1≤m≤2⋅105),表示数组 a a a和数组 b b b的长度。
每个测试用例的第二行包含 n n n个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an ( 1 ≤ a i ≤ 1 0 9 ) (1 \leq a_i \leq 10^9) (1≤ai≤109),表示数组 a a a的元素。
每个测试用例的第三行包含 m m m个整数 b 1 , b 2 , … , b m b_1, b_2, \ldots, b_m b1,b2,…,bm ( 1 ≤ b i ≤ 1 0 9 ) (1 \leq b_i \leq 10^9) (1≤bi≤109),表示数组 b b b的元素。
保证所有测试用例中 n n n的总和不超过 2 ⋅ 1 0 5 2\cdot 10^5 2⋅105, m m m的总和不超过 2 ⋅ 1 0 5 2\cdot 10^5 2⋅105。
输出
对于每个测试用例,输出 n + m n + m n+m个数字,即插入后获得的最终数组 c 1 , c 2 , … , c n + m c_1, c_2, \ldots, c_{n+m} c1,c2,…,cn+m的元素,使得 LIS ( c ) \text{LIS}(c) LIS(c)的值最小化。如果有多个答案,可以输出其中任意一个。
注意
第一个测试用例中, LIS ( a ) = LIS ( [ 6 , 4 ] ) = 1 \text{LIS}(a) = \text{LIS}([6, 4]) = 1 LIS(a)=LIS([6,4])=1。我们可以在 6 6 6和 4 4 4之间插入数字 5 5 5,然后 LIS ( c ) = LIS ( [ 6 , 5 , 4 ] ) = 1 \text{LIS}(c) = \text{LIS}([6, 5, 4]) = 1 LIS(c)=LIS([6,5,4])=1。
第二个测试用例中, LIS ( [ 1 ‾ , 7 , 2 ‾ , 4 ‾ , 5 ‾ ] ) \text{LIS}([\underline{1}, 7, \underline{2}, \underline{4}, \underline{5}]) LIS([1,7,2,4,5]) = 4 4 4。插入后, c = [ 1 , 1 , 7 , 7 , 2 , 2 , 4 , 4 , 5 , 5 ] c = [1, 1, 7, 7, 2, 2, 4, 4, 5, 5] c=[1,1,7,7,2,2,4,4,5,5]。很容易看出 LIS ( c ) = 4 \text{LIS}(c) = 4 LIS(c)=4。可以证明无法使 LIS ( c ) \text{LIS}(c) LIS(c)小于 4 4 4。
为了使插入的 b b b 数组对 LIS \text{LIS} LIS 的贡献最小,我们很容易想到插入的 b b b 数组中各个元素的大小应该是降序的。
这种情况下,对于 a a a 中的每个上升子序列, b b b 中最多只会有一个元素对其做出了贡献(假设有两个做出了贡献,那么这两个构成降序序列,破坏了整体的升序性质)。
那么就不难得到: LIS ( a ) ≤ LIS ( c ) ≤ LIS ( a ) + 1 \text{LIS}(a) \le \text{LIS}(c) \le \text{LIS}(a)+1 LIS(a)≤LIS(c)≤LIS(a)+1。
现在我们考虑能不能找到一种插入方法,使得 LIS ( a ) = LIS ( c ) \text{LIS}(a) = \text{LIS}(c) LIS(a)=LIS(c) 恒成立。
答案是有的。那就是把 c c c 数组分成若干组,使得每一组中只有最多只有一个元素出现在某个上升子序列中。上边这句话有没有一种熟悉的感觉?是不是和上边第二段的让 b b b 数组降序的想法很相似?所以这里我们让 c c c 中的每一组内部都成降序分布。
具体来说,我们降序排序好 b b b 后,顺序遍历 a a a 数组,把当前 b b b 中剩余的满足 b j ≥ a i b_j \ge a_i bj≥ai 的元素加到 a i a_i ai 左边( a i − 1 a_{i-1} ai−1 右边)。配合代码更好理解。
C o d e Code Code
#include
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int n, m;
int a[N], b[N];
void solve(int Case) {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= m; i ++) cin >> b[i];
sort(b + 1, b + m + 1, greater<int>());
int j = 1;
for (int i = 1; i <= n; i ++) {
while (j <= m && b[j] >= a[i]) {
cout << b[j ++] << " ";
}
cout << a[i] << " ";
}
while (j <= m) {;
cout << b[j ++] << " ";
}
cout << "\n";
}
signed main() {
cin.tie(0)->ios::sync_with_stdio(false);
int T = 1;
cin >> T; cin.get();
int Case = 0;
while (++ Case <= T) solve(Case);
return 0;
}