CF809C - Find a car 题解
终于把这题 A 掉了,感动中国(
做这题也是一波三折啊……几天前想的时候想假掉了,交上去 T 了,然后咕了好几天一直咕到现在。然后这数位 DP 又不是一般的难写,写的过程中心态崩过几次。然后又不是一般的难调,调出来之后交上去又 WA 了……然后发现是爆 ll
了,改成 __int128_t
上去,又 CE 了……只好手动把爆炸的地方改过来才 AC。
首先打个表发现这是一个分形,形式化的表述就是 \(a=\begin{bmatrix}a&a+n_a\\a+n_a&a\end{bmatrix}\)。然后我就直接递归了,写得像二维线段树一样,以为是二次对数的。但其实这个是假的,因为二维线段树是横着竖着各分为若干个整区间,横竖独立,而这个除此之外还要满足横竖相等(即是个正方形)。
然后就自爆了,就看题解了。发现一个结论:\(a_{i,j}=(i-1)\oplus(j-1)+1\)。那么到底怎么才能发现这个结论我也是不知道的,因为我要智商没智商,要眼力没眼力。
我们考虑将所求问题二位前缀和一下,那么问题归约到求 \(\sum\limits_{i=0}^x\sum\limits_{j=0}^y[i\oplus j<k]((i\oplus j)+1)\)。这也是个比较难的问题。考虑类似数位 DP(二进制)地统计答案:将 \(x,y\) 分别拆成位数比原数低的、和原数的一个前缀后面随便加的一些,这样每部分都是一个固定的前缀后面有若干位随便放的这个形式,并且数量是对数级别的。现在我们只要求,两个这样形式的数的上面那个 \(\sum\) 的值是多少,并且还要是常数时间,这样总时间复杂度是二次对数。
这个就分类小讨论一下即可。注意到局面是下面这个样子的:
.----.----------.
| h1 | z1 |
.----.-----.----.
| h2 | h2 |
.----------.----.
| k |
.---------------.
那么显然可以分为三段。第一段上下的异或和是固定的,那么就讨论一下与 \(k\) 的这段的大小。如果大那就为 \(0\),如果小那就后面随便取(这个很容易算出式子,等差数列也可以搞定),如果相等就继续往下。然后看第二段,这个第一个数的部分是自己取的,第二个数的部分是固定的。于是分小于和等于 \(k\) 这部分两种加起来。小于的话后面随便取,容易列式;等于的话,后面要小于,也容易。
代码异常难写,细节多的一批。我第一遍写完后只有一个错误也是蛮了不起的。