题目大意
B 君希望以维护一个长度为$n$的数组,这个数组的下标为从$1$到$n$的正整数。
一共有$m$个操作,可以分为两种:
- $0 \ l \ r$:表示将第$l$个到第$r$个数$(a_l,a_{l+1},\ldots,a_r)$中的每一个数$a_i$替换为 $c^{a_i}$,即$c$的$a_i$次方,其中$c$是输入的一个常数,也就是执行赋值
- $1 \ l \ r$:求第$l$个到第$r$个数的和,也就是输出:
因为这个结果可能会很大,所以你只需要输出结果$\bmod p$的值即可。
题目分析
第一眼:又是类似「THUSC2015」平方运算的强行题,找循环节。
第二眼:好像不是。。。
想法一:那就是线段树瞎搞一波强行$\log n$了。
第三眼:好像不能取模啊。。。
想法二:$p$应该是素数,欧拉函数强行取模。
第四眼:好像不是素数。。。搞毛啊。。。
冷静分析一波。
嗯,好像以前用过一个不需要$a,p$互素的降幂方法。
没错,上扩展欧拉定理。
其中$x\ge\varphi(m)$。
嗯,很不错。
然后我们套用到$0$操作上。
再来一层:
发现还可以继续套公式(建议放大食用):
这样不断嵌套,在$O(\log n)$次嵌套后$\varphi(\varphi(\cdots (p)))$就会变成$1$(见这里的证明),因此原式的值就不会变了。
若出现上述情况,在线段树中就不必要再次修改,直接返回即可。
接下来我们考虑快速修改维护答案。
原式中中括号部分是没法进行取模操作的,因此无法对答案直接维护。转而考虑维护嵌套次数。
因为有上述公式,因此给定初值与嵌套次数,就可以在$O(\log n)$的时间内计算出当前的值。
故每次修改,若未超过阈值,增加一下嵌套次数,重算一下答案即可。
考虑时间复杂度,每次修改的时间是$O(\log^3 n)$的,因为需要进行快速幂。
这会被卡常卡得很惨,可以采取一些奇奇怪怪的技巧来避免快速幂。
要求的是$c^x\bmod p(x\le 2^{32})$,利用meet-in-the-middle的思想,先预处理出$pow_1(n)=c^n\bmod p(n\le 2^{16})$以及$pow_2(n)=c^n(n\le 2^{16})$平方$16$次$\bmod p$的值,然后询问$c^x\bmod p$可以通过分两段查表解决:1
pow1[b&65535]*pow2[b>>16]%mod
另外,根据Sengxian大佬的验证:
指数循环节公式只在$x\ge \varphi(n)$时成立,在 UVa 10692 中,用试乘来判断是否$\ge \varphi(n)$,我们在试乘的时候,是以上一层返回的取模后结果作为幂试乘,这样并不准确,应该使用上一层的答案进行试乘。但是放心,经过验证,这样做没有任何问题。因为如果$x\ge \varphi(n)$,那么$a^x\ge n$只在$n=6$时不成立,经过验证,这个带来的一系列后续影响不会造成答案的错误,所以大可放心使用。
分析时间复杂度,每个数在$O(\log n)$次修改后会不变,消耗$O(n\log^2 n)$的时间。故总时间复杂度为:
可能有点小卡常。
代码
1 |
|