AGC044 简要题解(部分)
- A
乍一看数据范围非常唬人,但是仔细思考一下就可以发现这样一个事实:
从 \(x\) 逆着执行操作回到 \(0\) 的时候,除了最后一次连续执行若干次 \(-1\) 操作直至 \(0\) 之外,其余的时候,每两次除法之间,用 \(\pm1\) 造成的增量只会在 \([-2, 2]\) 之间。实际上,如果下一次除数是 \(2\) 或 \(3\),那么增量只会在 \([-1, 1]\) 之间。证明只需要考虑,如果移动路线是 \(x\rightarrow (x-1)\rightarrow (x-2)\rightarrow (\frac{x}{2}-1)\),那么走 \(x\rightarrow \frac{x}{2}\rightarrow (\frac{x}{2}-1)\) 不会使答案变劣,另外两个除数同理。
由于除法必须能够整除才可以执行,可以发现上述过程每步最多产生 \(4\) 个后继状态,并且这些状态大部分都是相同的。用堆和 map
维护每个状态的最短路,搜一下可以发现状态数大约只有 \(2\times 10^5\) 左右。
- B
考虑维护每个位置的最短路。每次一个人离开座位时,经过他的位置的代价 \(-1\);考虑以他的位置为起点,bfs 出所有 “以他的位置作为中转站” 可以使最短路变短的其他位置。这么做看起来是 \(O(n^4)\) 的,但是注意到所有被 bfs 到的点最短路都会减少 \(1\),而所有点最短路的总和是 \(O(n^3)\) 级别的。因此 bfs 的过程均摊下来是 \(O(n)\) 的。
- C
这题 dyls 出过一个基本上一模一样的(
如果只有操作 \(1\),只需要用一个置换来维护三进制表示中,最初的某个值(\(0, 1, 2\))实际上表示的是哪个值。现在加入了操作 \(2\),让我们考虑它实际上会影响哪些数的表示方式。
首先对于所有数的最低位,都向后滚了一位,即 \(0\rightarrow 1, 1\rightarrow 2, 2\rightarrow 0\)。然后是之前的最低位实际表示是 \(2\) 的那些数,它们的次低位也要向后滚一位(加法进位),而这个过程又会产生新的加法进位。可以发现,这是个递归的过程,一直到最高位的时候才会发生取模从而消除进位。这提醒我们,可以用一棵三进制字典树来维护所有数,由一个全局的置换来维护每个节点的每个儿子实际上表示的是哪个值。如果我们将字典树的高低位翻转(也就是 FFT 里的 bitrev 操作),那么这个过程影响到的点恰好是一条链,只需要 \(O(n)\) 修改这条链上点每个值对应的儿子即可。
- D
每次我都是恰好差一点想到正解(
丢人,我自己退出战场(
首先考虑一下,假如字符集是 0, 1
怎么做。我们可以先分别询问一个长度为 \(L\) 的全 0
串和全 1
串,不难发现,假如实际上有 \(x\) 个 0
,而实际串长为 \(|S|\),我们可以先取前 \(|S|\) 个字符中是 0
的位置,将剩余位置替换,并将最后 \(L-|S|\) 个位置削除。这样编辑距离为 \(L-x\),并且显然不存在更小的编辑距离。也就是说,设字符集大小为 \(m\),我们可以用 \(m\) 次询问得到每个字符的出现次数。
还是回到字符集是 0, 1
的情况。设 0
出现了 \(x\) 次,1
出现了 \(y\) 次。考虑逐位确定每一个字符是 0
还是 1
,但是我们并不能直接询问某个位置的字符;假设我们需要判断 \(S_1\) 是不是 0
,可以询问 011...11
,其中后半部分有 \(y\) 个 1
。由于 1
的个数恰好够用,这一个 0
的出现并不能动摇 1
的地位——如果 \(S_1\) 确实是 0
,那么编辑距离一定是 \(|S|-y-1\),但是如果 \(S_1\) 不是 0
,那么最优的编辑距离必然是将最前面的 0
删掉,再把所有的 0
依次插到合适的位置中去(否则至少要删掉一个 1
再把它加到这个 0
前面,或者修改至少两个位置的值,不会比删掉一个 0
的代价还多)。
确定了 \(S_1\) 之后,我们考虑依次确定 \(S\) 的每个位置,可以发现,只需要令 \(S'\) 表示已确定的部分,询问 \(S'+\) 011...11
即可,其中后半部分 1
的数量等于未确定位置的 1
数量。
实际上,我们上面的过程是在合并两个字符集交集为空的子序列。
只要注意到这个事实,就会发现之前的操作并不局限于 0
和 1
,只要待合并的两个部分的字符集交集为空,这一系列的过程都没有本质区别。
因此,设 \(\Sigma\) 表示字符集大小,询问的总次数是 \(O(\Sigma+L\log_2\Sigma)\) 级别的,可以通过。
- E
实际上,USACO 有一道题(18DEC Platinum——Balance Beam)是这个题的一部分。
在 USACO 版本里,序列并非是一个环,到达两个端点后游戏会自动结束(并获得 \(0\) 的收益),且移动一步不需要任何代价。不难发现,由于移动不需要任何代价且每一步面临的局面是无记忆性的,只需要确定到达每个点时是否结束游戏,就可以求出每个点的期望收益。
假设当前落脚点为 \(x\),如果 \(x\) 是结束点,显然收益就是 \(a_x\);否则,假设左、右最近的结束点分别是 \(l, r\),不难发现,从 \(x\) 随机游走,走到 \(l, r\) 的概率分别是 \(\frac{r-x}{r-l}\) 和 \(\frac{x-l}{r-l}\)。因此,在 \(x\) 点的期望收益就是 \(\frac{r-x}{r-l} a_l+\frac{x-l}{r-l} a_r\)。实际上,如果将每个停止点的位置作为横坐标,收益作为纵坐标的话,每个非停止点 \(i\) 的期望收益恰好就是两端最近的停止点确定的一次函数,在 \(x=i\) 时的纵坐标。
这个时候,就可以发现,由于凸包内任意选两个点,连出的线段都不会在凸包外,只需要将所有点 \((i, a_i)\) 建立一个上凸壳,取凸壳上的点作为停止点即可。
回到原题,发现序列变成了环,且每走一步都会付出不同的代价。环的限制其实很好解决:注意到玩家走到任意一个最大值时必然不会再走,可以在最大值处将环断成序列。但是如果每走一步都要付出代价,就无法套用上面的凸包。
先列出原始的式子:\(f_i=\max(a_i, \frac{f_{i-1}+f_{i+1}}{2}-b_i)\),而我们希望的式子是 \(g_i=\max(a'_i, \frac{g_{i-1}+g_{i+1}}{2})\),于是考虑构造出一个 \(c_i=f_i-g_i\),再由 \(c_i\) 和 \(a_i\) 构造出 \(a'_i\),就可以用上面的凸包方法求出所有的 \(g_i\) 了。考虑 \(g_i=f_i-c_i=\max(a_i-c_i, \frac{f_{i-1}+f_{i+1}}{2}-b_i-c_i)=\max(a_i-c_i, \frac{g_{i-1}+c_{i-1}+g_{i+1}+c_{i+1}}{2}-b_i-c_i)\)。这时候注意到,如果 \(\frac{c_{i-1}+c_{i+1}}{2}-b_i-c_i=0\),那么令 \(a'_i=a_i-c_i\) 的话,就恰好满足上面的条件。至于 \(c_i\) 的求法,注意到 \(c_i\) 有 \(n+1\) 个,但只有 \(n-1\) 个方程,因此可以直接令 \(c_0=c_n=0\),然后就可以两边递推求出 \(c_i\) 了。
可能是我写法问题,但是本题略微卡精度,需要 long double
才能通过。