CF809C - Find a car 题解

终于把这题 A 掉了,感动中国(

做这题也是一波三折啊……几天前想的时候想假掉了,交上去 T 了,然后咕了好几天一直咕到现在。然后这数位 DP 又不是一般的难写,写的过程中心态崩过几次。然后又不是一般的难调,调出来之后交上去又 WA 了……然后发现是爆 ll 了,改成 __int128_t 上去,又 CE 了……只好手动把爆炸的地方改过来才 AC。


Portal

首先打个表发现这是一个分形,形式化的表述就是 \(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\) 这部分两种加起来。小于的话后面随便取,容易列式;等于的话,后面要小于,也容易。

代码异常难写,细节多的一批。我第一遍写完后只有一个错误也是蛮了不起的。

code

posted @ 2020-11-17 22:51  ycx060617  阅读(115)  评论(0编辑  收藏  举报