CF2021

tai-chi / 2024-10-07 / 原文

A

题意

给一个长为 \(n\) 的数组 \(a\),每次可以选择两个元素 \(a_i,a_j\) 删除并加入元素 \(\left\lfloor \frac{a_i+a_j}{2} \right\rfloor\),最大化最终剩下的元素。

分析

每次操作相当于将一部分数大小减半,贪心地,将值小的放在前面,值大的放在后面,这样可以保证值大的数减半次数较小。

实现可以用优先队列,时间复杂度 \(O(n \log n)\)

B

题意

给一个长为 \(n\) 的数组 \(a\),每次可以选择一个 \(a_i\)\(a_i \leftarrow a_i+x\),问最佳策略下 \(a\)\(\operatorname{MEX}\)

分析

维护一个桶 \(cnt\),从小到大遍历 \(cnt\),发现 \(cnt_i=0\) 则找到了 \(\operatorname{MEX}\),如果 \(cnt_i > 1\) 则将其中的每个元素都加上 \(x\),即只留一个,剩下的都往后丢。

时间复杂度 \(O(n)\)

C1

题意

给长为 \(n\) 的数组 \(a\) 表示成员的位置,长为 \(m\) 的数组 \(b\) 表示希望成员完成任务的顺序,第 \(i\) 轮取出 \(a_1\)\(b_i\) 比较,要求 \(a_1=b_i\),比较完再把 \(a_i\) 插回 \(a\) 中任意位置,问一组 \(a,b\) 是否合法。

分析

注意到一个 \(b\) 合法当且仅当所有首次出现的数单调递增。

理由:不是首次出现的数总能通过适当地插入构造出合法解。

void solve()
{
	int n,m,q; cin>>n>>m>>q;
	vector<int> a(n+5),b(m+5);
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) cin>>b[i];
	vector<int> vis(n+5);
	int p=0;
	for(int i=1;i<=m;i++)
	{
		if(vis[b[i]]) continue;
		if(a[p+1]==b[i]) p++, vis[a[p]]=1;
		else {cout<<"TIDAK"<<endl; return;}
	}
	cout<<"YA"<<endl;
}