比赛链接
A. Double Perspective
把读入的数对直接按照边处理,取出每个连通块。
对于一个连通块,编号最大值为 imax,编号最小值为 imin。注意到 imax 和 imin 间有一条路径,这条路径在算 f(S) 时包覆盖了 [imin,imax] 这一整段区间。所以整个连通块覆盖的区间 [imin,imax]。
于是取每个连通块的任意生成树。此时 imax 和 imin 仍然联通,覆盖的区间没有变化。而此时 g(S) 变成了 0,所以方案是最优的。
时间复杂度可以做到 O(n)。题目的数据范围显然是为 O(n2) 设计的,赛时还以为自己想错了。
B. Stay or Mirror
把 ai 变成 2n−ai 这种操作,我下文称其为“反转”。
考虑 (i,j)(i<j) 何时能成为逆序对:
- ai<aj:ai 反转则为逆序对,否则不是逆序对。
- ai>aj:aj 不反转则为逆序对,否则是逆序对。
O(n2) 地枚举每一对 (i,j),对每个数字统计它反转时和不反转时的贡献。每个数字的两种贡献取最小值,加起来,就做完了。
C. Interactive RBS
在区分我的位置放构造题,恶心我是吧(
想要确定整个字符串,我们首先要找到任意一个 (
的位置 L,以及任意一个 )
的位置 R。
题目保证至少有一个 (
和一个 )
,因此至少有一个子串为 ()
或 )(
。我们考虑如何找到这个子串。
我们想要判断一个子串是否含有 ()
子串,直接询问这个子串即可。答案为 0 则不包含 ()
子串,否则包含。判断 )(
同理,反着询问这个子串即可。
首先询问一次整个字符串,以判断它是否包含子串 ()
。如果包含,我们就在字符串里找 ()
,否则我们就在字符串里找 )(
。
然后我们可以二分,每次判断 [l,mid] 区间内是否包含想找的子串即可。
这样,我们就找到了一个 (
和一个 )
。现在用掉了 1+⌈log2n⌉=11 次询问。
C1. Easy Version
现在我们还剩 500 多次询问次数,于是每次询问确定 2 个位置上的字符即可。
注意到如果想确定 i,j 处的字符,只需要询问:
(( i j ( j i
- 若答案为 0,则 si=(,sj=(。
- 若答案为 4,则 si=),sj=)。
- 若答案为 3,则 si=(,sj=)。
- 若答案为 2,则 si=),sj=(。
我们进行至多 500 次询问,就可以得出所有位置的字符。总询问次数不超过 511。
C2. Medium Version
在 C1 中,我们一次询问可以确定两个字符。我们考虑一次询问如何确定更多字符。
假设我们要确定 i0,i1,…,im 处的字符,则构造如下询问(中括号是为了方便理解,可以忽略):
⎣⎢⎡20个((…(( 20个i0 i0…i0 ⎦⎥⎤( ⎣⎢⎡21个((…(( 21个i1 i1…i1 ⎦⎥⎤( ⎣⎢⎡22个((…(( 22个i2 i2…i2 ⎦⎥⎤( … ( ⎣⎢⎡2m个((…(( 2m个im im…im ⎦⎥⎤
在这个构造中,如果 ij 位置上是 )
,则会对结果产生 2j 的贡献。于是把结果转换成二进制,就可以确定每一位的字符。
因为每次的询问长度不超过 1000,经过计算得出,一次询问可以确定 8 个位置。因此总询问次数为 11+⌈8n⌉=136。
C3. Hard Version
在 C2 中,我们用了一个性质:n 个括号嵌套,答案为 n。
但是此题中还有一个性质:n 个括号并列,答案为 2n(n+1)。
于是我们构造如下询问:
k1个 (i1(i1 (i1 …(i1 ( k2个 (i2(i2 (i2 …(i2 ( k3个 (i3(i3 (i3 …(i3 ( … ( km个 (im(im (im …(im
容易发现,如果 ij 位置上是 )
,则会产生 vj=2kj⋅(kj+1) 的贡献。否则贡献为 0。
我们考虑如何选取 kj,才能使询问结果 x 只对应一种答案。
不妨设 kj 递增,则需要满足:
vj≥d=1∑j−1vd
我们从 m 到 1 倒序枚举 j,如果 x≥vj,则 j 一定造成了贡献。我们就把 x 减去 vj,继续枚举,就能确定每一位的字符。
于是我们可以写一个程序,贪心地使 kj 尽可能小,且满足上述条件。我们发现,在询问长度合法时,m 最大可以取到 13。k1 到 k13 的取值如下:
1
| 1, 2, 3, 5, 7, 10, 15, 21, 30, 43, 61, 87, 123
|
因此,我们一次询问可以确定 13 个位置。总询问次数为 11+⌈13n⌉=88。