Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)
D. Take a Guess
题意
有一个长度为 N 的序列每次你可以询问两个值的与值和或值,求出原序列中第k大值。
询问不能超过 2N 次。
思路
与位运算有关的恒等式请见blog中的这篇文章,下文使用了文章中一些恒等式。
对 a+b=(a∣b)+(a&b) 的直接应用。
如果有了 a+b,a+c,b+c,那么很容易求出 a=2(a+b)+(a+c)−(b+c),而求每个 a+b 只需要两次询问,所以先求出第一个元素,那么后面所有的元素,都可以通过两次询问得出,询问次数 2N 次。
这里还有更优的方法,只需要询问 35N 次来自CF评论,还是考虑求出三元组:(a,b,c),但只通过5次询问 a&b,a∣b,a&c,a∣c,b&c,
先通过恒等式 a+b=(a∣b)+(a&b),求出 a+b,a+c,再通过恒等式 a⊕b=(a∣b)⊕(a&b),求出 a⊕b,a⊕c,
进一步可以求出来 b⊕c,于是再通过恒等式 b+c=2(b&c)+(b⊕c),可以得出 b+c,于是我们就可以通过5次询问,获得 a,b,c的值了!
下面代码所用的是 2N 次询问的做法:
点击显/隐代码
E. Equilibrium
题意
给出两个长度为 n 的序列 {an},{bn},你可以进行如下操作:
-
选择一个长度为偶数的严格单调递增序列:pos1<pos2<⋯<pos2k。
-
将 {an} 中对应下标为 pos1,pos3,⋯,pos2k−1 的数值都+1
。
-
将 {bn} 中对应下标为 pos2,pos4,⋯,pos2k 的数值都+1
。
接下来有 Q 次询问,每次询问给出一个区间 [l,r],求能否用若干次上述操作,使得 ai=bi,l⩽i⩽r。
如果可以输出最小的操作次数,否则输出-1
。
思路
由于每次操作,对数组 a,b 发生变化元素的个数和大小总是相同的,所以考虑将两者做差。
令 ci=bi−ai,若 ci 在 [l,r] 上满足以下两个条件,则一定有解:
-
∑i=lrci=0
-
∀k∈[l,r],∑i=lkci⩾0
第一个条件:因为每次 a,b 数组同时进行+1
,所以两者做差之和总是 0。优化方法,对 c 数组求前缀和。
第二个条件:不妨假设 cl<0,这说明 al>bl,又由于第一个元素只能是+1
,只会越加越大,所以不满足题意。优化方法,对 c 数组的前缀和数组求区间最大值和区间最小值,记最大值为 MAX,最小值为 MIN,如果 MIN−sum[l−1]<0 无解,否则答案即为 MAX−sum[l−1],因为只需要将最大的一块减成 0 就能保证其他小块都减成 0 了。
用ST表求区间最值,时间复杂度 O(nlogn+Q)
点击显/隐代码
H. DIY Tree
题意
给出 n 个点的完全图,并给出每条边的边权,求该图的生成树,使得前 k 的节点的度,不超过给定值,并要求整棵生成树的权值最小。(树的权值定义:树上所有边权之和。
数据范围:2⩽n⩽50,1⩽k⩽min(n−1,5)。
思路
从CF评论中学的模拟退火。
数据量较小。
-
先构造一个满足题意的生成树(比如所有节点都和 n 节点连边)
-
用模拟退火算法,每次随机删除、随机添加有效边。
时间复杂度不会 ′(*>﹏<*)′
下面代码使用了多次退火,卡时5500ms过的,正确率还行。
点击显/隐代码