CF1894 H Asterism Stream题解

1|0题意

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

  • 使 x1
  • 使 x2

问期望多少步操作可以使 x 大于 n , 输出期望步数模 998244353 的值。
其中 1n1018

2|0题解

2|1题目分析

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

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

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

2|2转移式推理

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

f(x)=12f(2x)+12f(x+1)+1

=12f(2x)+12(12f(2(x+1))+12f(x+2)+1)+1

=12f(2x)+12(12f(2(x+1))+12(12(f(2(x+2))+)+1)+1)+1

=i=0rx(12)i+1f(2(x+i))+i=0rx(12)i+(12)x+1f(r+1)

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

i=0rx(12)i+1f(2(x+i))

=i=0rx(12)i+1fg(a,b)(2(x+i))

=i=0rx(12)i+1fa(12)2b(x+i)

=i=0rx(12)i+1fa(12)2bx×(12)2bi

=fa(12)2bxi=0rx(12)i+1×(12)2bi

=fa(12)2bx×12i=0rx(12)i×(12)2bi

=fa(12)2bx×12i=0rx(12)i(2b+1)

=fa(12)2bx×12i=0rx((12)(2b+1))i

=fa(12)2bx×12×((12)(2b+1))rx+11(12)(2b+1)1

=fa(12)2bx×12(((12)(2b+1))rx+1(12)(2b+1)11(12)(2b+1)1)

=fa(12)2bx×12(((12)(2b+1))r+1(12)(2b+1)1×(12)(2b+1)x1(12)(2b+1)1×(12)0×x)

=fa×12(((12)(2b+1))r+1(12)(2b+1)1×(12)x1(12)(2b+1)1×(12)2bx)

=fg(a((12)(2b+1))r+1(12)2b2,1)(x)g(a(12)2b2,2b)(x)

=g(fa((12)(2b+1))r+1(12)2b2,1)(x)fg(a(12)2b2,2b)(x)

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

f(x)=g(f(r+1)12,1)(x)+g(2,0)(x)+g((12)k,1)(x)+g(fa((12)(2b+1))r+1(12)2b2,1)(x)fg(a(12)2b2,2b)(x)

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


__EOF__

本文作者FlowerDream
本文链接https://www.cnblogs.com/flower-dream/p/17663472.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   小篪篪  阅读(78)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
Live2D
欢迎阅读『CF1894 H Asterism Stream题解』
点击右上角即可分享
微信分享提示