题解:B4161 [BCSP-X 2024 12 月小学高年级组] 操作序列

看题解前:这题至少蓝吧?

看题解后:我太蓝了。

分享一种麻烦的做法。

本题的关键在于两类操作叠加在同一条序列里:全局乘 \(2\) 与单点加。若直接模拟,每一次都要扫一遍 \(n\) 个变量,不可能通过 \(2\times10^{5}\) 规模。解决办法是把模数 \(10000\) 拆成互质的 \(16\)\(625\),在两个较小模空间里分别维护序列,再用中国剩余定理把结果拼回去。这样既绕开了 \(2\) 在模 \(10000\) 下没有乘法逆元的问题,又把复杂度降到线性。

在模 \(625\) 中,\(2\) 与模数互质,逆元为 \(313\)。顺着区间顺序扫描时只记录已经发生的乘 \(2\) 次数 \(t\);某个变量最后一次被单点修改时记下当时的 \(t\);真正存进数组的是已经乘好的值。为了让单点操作还是 \(O(1)\),把每条区间的整体权值拆成差分事件:区间左端点加,右端点后一个位置减。权值计算用 \(2^{k}\bmod625\);由于 \(\varphi(625)=500\),预处理 \(2^{0\sim499}\),指数直接取模 \(500\) 即可。逆元幂 \(313^{t}\) 也预乘成前缀表。于是整个模 \(625\) 部分只需一次线性扫描。

\(16\) 情况完全不同:\(2^{4}\equiv0\pmod{16}\),所以只要记录最后不超过三次乘 \(2\) 即可。把整条区间序列从尾到头扫一遍,一旦累计乘次数达到 \(4\) 就可以停止,因为更早的乘法对模 \(16\) 结果全被消去。根据乘次数 \(k=0,1,2,3\) 把剩余后缀拆成至多 \(4\) 段,用四个差分数组 \(s_0\sim s_3\) 统计段内出现的所有单点加,再顺序扫描一次即可求出模 \(16\) 值。

两套结果合并时利用 \(625\equiv1\pmod{16}\):令 \(a\) 是模 \(625\) 的答案,\(b\) 是模 \(16\) 的答案,最终 \(x=a+625\bigl((b-a)\bmod16\bigr)\)。这样省去了扩展欧几里得,只要一次取模和一次乘法。额外预处理和快速幂都是常数级,总时间复杂度 \(O(n+m+q)\)

link

posted @ 2025-07-06 17:30  薛儒浩  阅读(113)  评论(0)    收藏  举报