CF1894 H Asterism Stream题解

发布时间 2023-09-04 11:51:52作者: 小篪篪

题意

给定一个 \(n\) , 有一个初始为 \(1\) 的整数 \(x\) , 每次有相同概率进行以下两个操作的其中一种:

  • 使 \(x\)\(1\)
  • 使 \(x\)\(2\)

问期望多少步操作可以使 \(x\) 大于 \(n\) , 输出期望步数模 \(998244353\) 的值。
其中 \(1 \leq n \leq 10^{18}\)

题解

题目分析

如果从题解的角度来看, 这道题的解法可以说是极其不自然, 很多定义都有一种需要人类智慧的感觉。 所以我们从题目开始, 来一步步分析, 为什么会得到题解的做法。
首先, 分析数据范围, 不是一道可以加速的递推题就是一道结论题。 但因为结论题大多都能用递推加速做, 并且这个题目如果有结论, 样例也显现出这个结论是一个多项式, 而不是简单的特判加简短通式, 我们优先不考虑直接化结论, 毕竟最后就算是结论大不了就矩阵加速多个常数, 不是结论而想错方向浪费时间并且容易走进误区。
接着, 确认了大体算法方向后, 考虑是否答案的 \(f(n)\) 可以由前面相隔不远的几项, 比如 \(f(n - 1)\)\(f(n - 2)\) ...递推过来。 当然, 最终经过某位勇敢者的亲身尝试, 证明这确实是正确的(直接粘一个 BM 的板子很符合我对网赛的想象), 可我们并不能从题目的暴力递推式和各种变形中证明这一点, 而中国的 OIer 们还要面对 \(NOI\) 赛制, 所以不建议在没有结论支持的时候使用 BM 这种算法, 当然, 论骗分, 直接码就行, 都不带怕的。
然后, 我们考虑两种最暴力的方法: 暴力枚举和简单 dp
先说一下简单 dp, 一般来说, 加速递推都是由简单 dp 的式子经过一系列的优化产生, 而这个过程中有一个比较烦人的点是, 如果有几乎 \(O(n)\) 个结束位置或者结束位置很难找到, 那么我们的加速就会变得复杂, 所以我们优先考虑能让结束位置比较优秀的状态。 那么我们定义 \(f(x)\) 表示 \(x\) 变到大于等于 \(n\) 的期望步数。 这样定义后, 可以发现, 初始状态是 \(f(x) = 0( n\leq x \leq 2(n - 1))\) 。 这里给了我们提示, 如果初始状态都是一段一样的, 那是不是前面的部分也可以分成几段, 每段都是一个结果或者有通式呢?
再来看一下直接暴力。 因为每一步都会使 \(x\) 更接近于结束状态, 所以我们可以写出一个非常无脑的暴力, 枚举所有的操作, 算贡献。 观察一种情况的贡献是 \(0.5^{s}s\) , 其中 \(s\) 是这种情况的操作步数。 再观察最终的答案, 可以发现, 贡献的种类比情况数少很多, 这启示我们可能有些东西是可以合并的, 而 \(f(x)\) 又和 \(x\) 强相关, 那么我们可以联想到创造一个函数 \(g(x)\), 使得 \(g(x)\) 满足以下两点要求:

  • 对于每个 \(f(x)\) , 都能使用少量的 \(g(x)\) 表示出来
  • \(g(x)\) 是简单函数, 及不含 \(\sum\)\(\Pi\) 、 判断等

由于第一个要求, \(g(x)\) 和暴力的贡献大概率有着一些联系, 一般来说 \(g(x)\) 中会有贡献里比较特别、 难算、 有性质的项。 那这道题举例, \(0.5^ss\) 中的 \(s\) 太过普通, 感觉上就没啥用, 加上了甚至可能会妨碍我们化简。 而 \(2^s\) 就很特别, 不是特别好算, 但又有一些性质, 所以 \(g(x)\) 中大概率会有类似的项。 本着在所有可能的地方加未知数的原则, 我们就可以合理推测出 \(g(x)\) 的最终形式应该是 \(g_{(a, b)}(x) = a(\dfrac{1}{2})^{bx}\) 也许有人会好奇为什么这里没有常数项, 这是因为常数项可以用 \(g_(a, 0)(x)\) 来表示, 并且就算不是这种形式的 \(g(x)\), 也应该独立计算, 因为如果把常数项放在 \(g(x)\) 考虑就会出现分配问题, 化式子的时候容易出错。

转移式推理

注:本部分来自于 codeforces 赛后题解, 如有不懂, 可以点击此处跳转查阅
有了基本思路和算法方向, 我们就可以来推一推式子, 套一套优化了。
由于前面的分析, 我们有了 \(f(x)\) 是可以分成一段一段的, 每一段都有通式。 那么我们来看看如何求区间 \((l, r)\) 的通式, 这个区间有通式又需要满足什么。
首先我们一步一步地推理, 如果 \([l, r]\) 有通式, 那么需要知道什么?
在此区间内, 有:

\[f(x) = \dfrac{1}{2}f(2x) + \dfrac{1}{2}f(x + 1) + 1 \]

\[= \dfrac{1}{2}f(2x) + \dfrac{1}{2}(\dfrac{1}{2}f(2(x + 1)) + \dfrac{1}{2}f(x + 2) + 1) + 1 \]

\[= \frac{1}{2}f(2x) + \frac{1}{2}(\frac{1}{2}f(2(x + 1)) + \dfrac{1}{2}(\dfrac{1}{2}(f(2(x + 2)) + \ldots) + 1) + 1) + 1 \]

\[= \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}f(2(x + i)) + \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i} + (\dfrac{1}{2})^{x + 1}f(r + 1) \]

这里我们直接将所有括号暴力展开, 化简得出了这个式子, 然后我们再一项一项地考虑化简成几个 \(g(x)\)
首先 \((\dfrac{1}{2})^{x + 1}f(r + 1)\) 就是 \(g_{(f(r + 1)\dfrac{1}{2}, 1)}(x)\) , 注意这里的 \(f(r + 1)\) 是常数, 并不是一个式子。
接着再看 \(\sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i}\) 这一项, 这个比较简单, 直接上等比数列求和, 得到 \(g_{(2, 0)}(x) + g_{(-(\dfrac{1}{2})^k, -1)}(x)\)
最后再来看最麻烦的一项, \(\sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}f(2(x + i))\)
由于这一项有多个 \(f(x)\) 求和, 而不同的 \(f(x)\) 之间的联系不太紧密, 不好化简, 所以考虑增加条件, 及 \(f(2(x + i))\)\(f(x)\) 是有同样的通项公式的, 也就是说 \([2l, 2r]\) 有通项公式。 这样化简起来就要方便许多了。
\(f(x) = \sum\limits_{f} g_{(a, b)}(x)\) , 那么有:

\[\sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}f(2(x + i)) \]

\[= \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}\sum\limits_{f} g_{(a, b)}(2(x + i)) \]

\[= \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}\sum\limits_{f} a(\dfrac{1}{2})^{2b(x + i)} \]

\[= \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1}\sum\limits_{f} a(\dfrac{1}{2})^{2bx} \times (\dfrac{1}{2})^{2bi} \]

\[= \sum\limits_{f} a(\dfrac{1}{2})^{2bx}\sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i + 1} \times (\dfrac{1}{2})^{2bi} \]

\[= \sum\limits_{f} a(\frac{1}{2})^{2bx} \times\frac{1}{2} \sum\limits_{i = 0}^{r - x}(\frac{1}{2})^{i} \times (\frac{1}{2})^{2bi} \]

\[= \sum\limits_{f} a(\dfrac{1}{2})^{2bx} \times\dfrac{1}{2} \sum\limits_{i = 0}^{r - x}(\dfrac{1}{2})^{i(2b + 1)} \]

\[= \sum\limits_{f} a(\dfrac{1}{2})^{2bx} \times\dfrac{1}{2} \sum\limits_{i = 0}^{r - x}((\dfrac{1}{2})^{(2b + 1)})^{i} \]

\[= \sum\limits_{f} a(\dfrac{1}{2})^{2bx} \times\dfrac{1}{2} \times \dfrac{((\frac{1}{2})^{(2b + 1)})^{r - x + 1} - 1}{(\dfrac{1}{2})^{(2b + 1)} - 1} \]

\[= \sum\limits_{f} a(\dfrac{1}{2})^{2bx} \times\dfrac{1}{2} (\dfrac{((\frac{1}{2})^{(2b + 1)})^{r - x + 1}}{(\frac{1}{2})^{(2b + 1)} - 1} - \dfrac{1}{(\dfrac{1}{2})^{(2b + 1)} - 1}) \]

\[= \sum\limits_{f} a(\frac{1}{2})^{2bx} \times\dfrac{1}{2}(\frac{((\dfrac{1}{2})^{(2b + 1)})^{r + 1}}{(\dfrac{1}{2})^{(2b + 1)} - 1} \times (\frac{1}{2})^{-(2b + 1)x} - \dfrac{1}{(\frac{1}{2})^{(2b + 1)} - 1}\times (\dfrac{1}{2})^{0 \times x}) \]

\[= \sum\limits_{f} a \times\dfrac{1}{2}(\dfrac{((\frac{1}{2})^{(2b + 1)})^{r + 1}}{(\dfrac{1}{2})^{(2b + 1)} - 1} \times (\dfrac{1}{2})^{-x} - \dfrac{1}{(\frac{1}{2})^{(2b + 1)} - 1}\times (\dfrac{1}{2})^{2bx}) \]

\[= \sum\limits_{f}g_{(\dfrac{a((\frac{1}{2})^{(2b + 1)})^{r + 1}}{(\frac{1}{2})^{2b} - 2}, -1)}(x) - g_{(\dfrac{a}{(\frac{1}{2})^{2b} - 2}, 2b)}(x) \]

\[= g_{(\sum\limits_{f}\dfrac{a((\frac{1}{2})^{(2b + 1)})^{r + 1}}{(\frac{1}{2})^{2b} - 2}, -1)}(x) - \sum\limits_{f}g_{(\dfrac{a}{(\frac{1}{2})^{2b} - 2}, 2b)}(x) \]

我们将几个式子合起来, 就能得到

\[f(x) = g_{(f(r + 1)\dfrac{1}{2}, 1)}(x) + g_{(2, 0)}(x) + g_{(-(\dfrac{1}{2})^k, -1)}(x) + g_{(\sum\limits_{f}\dfrac{a((\frac{1}{2})^{(2b + 1)})^{r + 1}}{(\frac{1}{2})^{2b} - 2}, -1)}(x) - \sum\limits_{f}g_{(\dfrac{a}{(\frac{1}{2})^{2b} - 2}, 2b)}(x) \]

所以我们只要保证通过 \(O(\log(n))\) 次或者类似的比较少的次数递推得到 包含 \(1\)\([l, r]\) 即可。
考虑我们为了推式子给出的条件是得到 \([l, r]\) 需要知道 \([2l, 2r]\) , 而最开始的一段已知的具有通项公式的段是 \([n, 2n - 1]\) , 我们可以从这一段开始递推, 每次去求 \([\lceil \frac{l}{2} \rceil, \lfloor \frac{r}{2} \rfloor]\) 就可以了, 另外注意一点, 由于初始的区间是 \([n, 2n - 1]\) 所以我们能保证任意时候的区间 \([l, r]\) 都有 \(r + 1\) 属于上一次的区间, 也就是可以直接求出 \(f(r + 1)\) 的值。
最后因为左端点要等于 \(1\) 需要 \(\log(n)\) 次, 所以总时间复杂度是 \(O(T\log^2(n))\) 或者 \(O(T\log^3(n)\) , 这里的时间复杂度差别在于快速幂。