题解:CF1893B Neutral Tonality

CF1893B 题解

题面

原题传送门

题意

给定两个数组 \(a,b\),构造一个序列 \(c\),使得其包含 \(a,b\) 中的所有元素,保证 \(a\) 在其中的相对顺序不变,且最长(严格)上升子序列(\(\text{LIS}(c)\))最短。

转化一下,也可以理解为,给定两个数组 \(a,b\),要求把 \(b\) 中的所有元素按照任意顺序插入 \(a\) 中,要求最终形成的数组的最长(严格)上升子序列最短。

思路

首先因为 \(a\)\(c\) 中的相对位置不变,所以必然有 \(\text{LIS}(c)\geqslant\text{LIS}(a)\)

那么就考虑如何插入 \(b\) 可以使得 \(\text{LIS}(c)=\text{LIS}(a)\),容易想到一种简单的构造方法,现将 \(b\) 从大到小排序,对于一个数 \(b[j]\),将它插入到第一个满足 \(a[i]\leqslant b[j]\)\(a[i]\) 前面,那为什么这样是 \(\text{LIS}(c)=\text{LIS}(a)\) 的呢?接下来开始证明。

首先,因为是插入到第一个满足 \(a[i]\leqslant b[j]\)\(a[i]\) 前面,所以在 \(a[i]\) 前面的所有数都小于 \(b[j]\),但是因为 \(a[i]\leqslant b[j]\),所以对于一个上升子序列,选 \(a[i]\) 肯定更优(至少是一样),要是有多个数插在同一个位置也不会影响答案,因为 \(b\) 已经被从大到小排序过,所以每次的插入不会改变序列的最长(严格)上升子序列。

那么,开始打代码吧~

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
const int MN=200005;
ll T,n,m,a[MN],b[MN];
bool cmp(ll x, ll y){return x>y;}
void write(ll n){if(n>9)write(n/10);putchar(n%10+'0');}
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
int main(){
	T=read();while(T--){
		n=read();m=read();for(int i=1; i<=n; i++) a[i]=read();for(int i=1; i<=m; i++) b[i]=read();
		sort(b+1,b+1+m,cmp);//从大到小排序 
		for(int i=1,p1=1,p2=1; i<=n+m; i++){
			if(p1>n||(p2<=m&&b[p2]>=a[p1])) write(b[p2++]),putchar(' ');
			else write(a[p1++]),putchar(' ');
		}
		putchar('\n');
	}
	return 0;
}
posted @ 2025-01-29 15:52  naroto2022  阅读(25)  评论(0)    收藏  举报