光速幂套扩展欧拉定理写吐了……
# 题面
> 洛谷 P3747
点击展开/折叠题面
维护一个长度为 $n$ 的数组 $A$,给定 $C,P$,对它进行 $m$ 次操作:
0 l r
表示将 $l$ 到 $r$ 的 $a_i$ 替换为 $C^{a_i}$;1 l r
求 $l$ 到 $r$ 的和对 $P$ 取模的结果。
# 解析
因为 $P$ 不是质数又要求一个幂对 $P$ 取模的结果,就容易想到欧拉定理;而且 $(C,P)$ 没有保证为 $1$,所以需要扩展欧拉定理。
然后我们看看连续对 $a_i$ 进行两次修改过后会变成什么样:
(那个 $d_i$ 是因为扩展欧拉定理 $C^a$ 如果 $a\ge \varphi(P)$ 就取模过后还要再加上 $\varphi(P)$,但是 $a<\varphi(P)$ 就不能加,所以写成这个样子方便一些)
然后我们发现有一个欧拉函数的嵌套,这样嵌套 $O(\log n)$ 次就会降到 $1$。降到 $1$ 过后就不会继续改变了,注意这里的降到 $1$ 是指嵌套到取模 $\varphi(1)$,而不是说取模到 $\varphi(\varphi(\dots\varphi(P)))=1$,不然的话只取模到 $\varphi(2)=1$ 会出问题。
记 $P$ 在嵌套 $k$ 次欧拉函数过后变成 $1$。然后区间修改时,我们对每个修改次数小于 $k$ 的点做一次暴力修改,即直接嵌套计算该点的幂值,因为 $k$ 为 $O(\log n)$,再套上快速幂的一个 $\log$,一个点修改一次的复杂度就是 $O(\log^2 n)$。
每个点最多修改 $k$ 次,$n$ 个点的总复杂度就是 $O(n\log^3 n)$。看起来有点问题,之后再说。
实现的话就是用线段树,如果当前区间中每个数都修改了超过 $k$ 次,就不进入修改,否则递归进去找修改小于 $k$ 次的数。
具体说说怎么暴力计算嵌套幂。
注意到扩展欧拉定理如果 $C^a$ 的 $a\ge\varphi(P)$ 是要再加 $\varphi(P)$ 的,所以在进行下面计算的时候:
判断 $d_2$ 是否是 $\varphi(P)$ 时,不能用 $C^{a\bmod \varphi(\varphi(p))+d_1}\bmod\varphi(P)$ 来和 $\varphi(P)$ 比较大小,为什么会有这个问题?因为我们写快速幂的时候会用 Pow(a,b,mod)
直接计算出 $C^{a\bmod \varphi(\varphi(p))+d_1}\bmod\varphi(P)$,所以快速幂的时候还要存一下是否已经取模了 $\varphi(P)$,如果取模了就说明了 $C^{a\bmod\varphi(\varphi(P))+d_1}\ge\varphi(P)$。
接下来再看复杂度的问题,可以看到多了一个 $\log$ 而且我们发现一个位置修改 $\log$ 次和每次修改需要嵌套 $\log$ 次免不掉,只能尝试砍一下快速幂。
我们发现快速幂的特点是底数一直都是 $C$……所以网上就有一个称作光速幂的东西。
因为模数不超过 $10^8$,我们令 $T=10^4+10$(反正 $T>10^4$ 就是了),然后把 $C^{x}$ 的 $x$ 拆成 $x_1T+x_2$($0\le x_2< T$)。我们只需要预处理 $C^{iT}$($0\le i\le T$) 和 $C^{i}$($0\le i< T$),然后就可以 $O(1)$ 计算了。
仍然要像快速幂一样记录是否已经取模,用一个 bool 数组储存一下,具体看看代码吧。
# 源代码
1 | /*Lucky_Glass*/ |
THE END
Thanks for reading!
> Linked 此生如歌-网易云