Codeforces Round 908 (Div. 2)

发布时间 2023-11-09 09:43:42作者: gan_coder

https://codeforces.com/contest/1894
A题题意说一堆,还看了好几次,读懂之后就很简单,直接输出最后的。
B题直接数一下有多少个大于2的块即可。
C题每次找到最后一个,判断一下即可,同时打上标记,保证时间复杂度。

D题手玩之后发现我们可以用以下方式插入b
将大于等于a的最大值的数从大到小插入到a的最大值的前面
将大于等于a的次大值的数从大到小插入到a的次大值的前面
······

将剩余的数直接从大到小放到最后

注意如果有相同插到最前面

证明的话可以大概归纳一下,
最大的情况是显然的

假如我们在前k-1次插入操作都是最优的,现在在第k大数前插入。
首先显然在组成上升子序列的时候是选择a中第k大的数更优,而不是选择在它前面插入的数更优秀,一方面,前面能够转移过来的集合是一样的,因为前k-1次插入的数以及前k-1大的数都大于它们,而结尾当然是越小越好,并且答案和原来一样且不能更小。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<ctime>
#include<unordered_map>
#include<queue>
#include<bitset>
#define A puts("Yes")
#define B puts("No")
#define fo(i,a,b) for (ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
#define eb(x) .emplace_back(x)
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
//typedef __int128 i128;
typedef double db;
typedef long long ll;
//const ll mo=1e9+7;
//const int inf=1<<30; // check
const int N=2e5+5;  // check 
ll n,m;
ll a[N],b[N];
struct node{
	ll x,id;
};
node c[N];
ll l[N],r[N];
bool bz[N];
bool cmp(ll a,ll b) {
	return a>b;
}
bool cmp1(node a,node b){
	if (a.x!=b.x) return a.x>b.x;
	return a.id<b.id;
}
int main()
{
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);

	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%lld %lld",&n,&m);
		fo(i,1,n) bz[i]=0;
		
		fo(i,1,n) {
			scanf("%lld",&a[i]);
			c[i].x=a[i];
			c[i].id=i;
		}
		fo(i,1,m) scanf("%lld",&b[i]);
		sort(b+1,b+m+1,cmp);
		sort(c+1,c+n+1,cmp1);
		
		int j=1;
		fo(i,1,n) {
			if (j>m) break;
			if (b[j]<c[i].x) continue;

			bz[c[i].id]=1;
			l[c[i].id]=j;
			while (j<m && b[j+1]>=c[i].x) j++;
			r[c[i].id]=j;
			
			j++;
		}
	
		fo(i,1,n) {
			if (bz[i]){
				fo(j,l[i],r[i]) printf("%lld ",b[j]);
				printf("%lld ",a[i]);
			}
			else printf("%lld ", a[i]);
		}
		fo(i,j,m) printf("%lld ",b[i]);
		printf("\n");
		
	}


	return 0;
}