P4681 [THUSC2015] 平方运算 题解
考虑模数给定,且给定模数最大为 \(9977\)。
这启示我们每个数字最多平方取模 \(9976\) 次就会开始重复。但是事实上可能要小得多,于是我们尝试打表验证规律。
打表程序:code
我们验证了确定模数时,所有数字的最多的不超过 \(11\) 次即可进入循环节,且所有循环节的 \(\text{lcm} \le 60\)。
事实上,这相当于对于每个 \(x\),连一条 \((x, x^2 \bmod p)\) 的边。
因为会出现循环节,这相当于形成了一棵内向基环树,而对于不同的循环节,我们形成了一个基环树森林。
而验证的东西其实就是环长。
对于找环,可以考虑拓扑排序。
我们想要用线段树维护它,但是当每个数字没有到循环节内时,我们确实没有办法维护这个整体,所以只能暴力。
而当对于某个区间已经全部踏进环内时,我们可以直接对该区间打上 整体在环上移动一步 的标记。
另外,对于一个区间来讲,如果左右区间 \(l, r\) 的循环节已经确定,那么和的循环节长度即为左右 \(l, r\) 循环节的 \(\text{lcm}\)。
- 对于复杂度,预处理为 \(O(n \log n)\)。
- 设每个数暴力的次数为 \(c_1\),则暴力部分的复杂度为 \(O(c_1n \log n)\),其中 \(c_1\) 上文已给出,最大为 \(11\)。
- 设循环节长度 \(\text{lcm}\) 为 \(c_2\),线段树上除了叶子节点每个点还会合并一个循环节,所以这部分的复杂度为 \(O(c_2\omega n)\),其中 \(c_2\) 取决于左右子区间循环节长度,上文给出过 \(\text{lcm}\) 最大为 \(60\),\(\omega\) 为线段树节点常数约为 \(4\)。
- 最后是打标记的复杂度,这部分即为 \(O(m \log n)\)。
所以总复杂度即为 \(O(c_1n \log n + c_2\omega n + m \log n)\)。