二次剩余Cipolla算法学习小记

Preface

今天 z 大神给我们讲数论和代数,然后后面讲了几个超级神的算法。 Cipolla 算是其中一个吧。貌似国内直接查名字还没有什么资料,查二次剩余的算法有ACdreamer简略的介绍。今天听讲时算是听懂了大半,回来又搞鼓了整个晚上才算完全弄明白。这个算法真的是从头到尾都是脑洞,太神了!
详细的解释见维基百科。

Paper

首先我们要弄清楚什么叫二次剩余,其实就是对于给定的 p(pP) n ,如果有 x 满足 x2n(modp) ,那么 n 在模 p 意义下就是二次剩余。说白了就是模意义下能否开根号。
我们只讨论 p 为奇素数的情况。
我们先定义 Fp ,这是一个数域,其实就是 0 p1 p 个数与模 p 意义下加减乘除运算构成的集合。

  • 定理1:对于 x2n(modp) ,总共有 p12 个的 n 能使该方程有解(将 n=0 情况除去,由于该情况显然有 x=0 )。
  • 证明:我们只用考虑所有 x2 。如果存在不同的两个数 u v ,它们的平方在模 p 意义下同余,那么显然有 p|(u2v2) 。由平方差公式 p|(u+v)(uv) 。显然 p 不可能整除 uv ,因此 p 整除 u+v ,因此 u+v0(modp) 。这个结论反过来也是成立的,因此共有 p12 种互不相同的平方,显然对应了所有有解的 n ,而且同一个 n 还一定存在两个互为相反数的解。

然后我们还要知道一个神奇的东西叫做勒让德符号( Legendre symbol )。
它是这样定义的

(ap)=1,1,0,apapa0(modp)

那我们怎么求该符号的值呢?

  • 定理2: (ap)ap12(modp)
  • 证明:
    • a 在模 p 意义下是二次剩余时,令 x2a(modp) ,那么就有 xp11(modp) ,由费马小定理,显然 x 存在。
    • a 在模 p 意义下不是二次剩余时,依旧令 x2a(modp) ,那么就有 xp11(modp) ,由费马小定理,显然 x 不存在。
    • a0(modp) 时显然满足。

那么我们就可以通过快速幂计算勒让德符号来判定一个数在模 p 意义下是否是二次剩余了。
有了这些理论基础,我们可以开始算法了。
首先我们要明确我们要求 x2n(modp) 的解 x (假定 n 在模 p 意义下是二次剩余,由定理1有两个互为相反数的可行解)。
算法一开始的时候我们首先要通过不断地随机(你没有听错,就是随机)出一个数 a ,使得 (a2np) 1 ,也就是不能开根号。先不要管为什么是 a2n ,我们来算算随机次数的期望。还是由定理1,一共有 p12 个数满足勒让德记号值为 1 ,因此一次随机得到结果的概率为 p12p 。当 p 够大的时候,这个概率是趋近于 12 的。那么列一下期望的树状图,就可以得到期望次数为 2
那么我们得到这个不能开根号的数之后要干什么呢?我们要干一件丧心病狂的事情,那个数不能开根号,我们非要给它一个域 Fp2 让它可以开根号(类比 1 所在的复数域)。我们将 a2n 定义为这个域的“虚数单位元”(类比 i=1 ),设它为 ω ,那么这个“复数域” Fp2 的数就一定可以表达为 a+bω (类比复数域 a+bi bω 相当于虚部)。
那么我们将复数域的四则运算法则全部类比到 Fp2 上面,显然它依然满足封闭性、交换律、结合律以及分配律的,还存在加法零元和乘法逆元(貌似符合环的定义)。具体看下图。
二次剩余Cipolla算法学习小记_第1张图片
那么它就是一个合法的数域。
然后我们定义这个数域有什么用呢?
x(a+ω)p+12(modp)
啊?就这么简单???
我们首先来证明一些东西:

  • 定理3: ωpω(modp)
  • 证明: ωpω×ωp1ω×(ω2)p12ω×(a2n)p12ω(modp)
  • 定理4: (a+b)nan+bn(modn)(nP)
  • 证明:使用二项式定理我们能得到
    (a+b)ni=0nCinaibni(modn)
    由于 n 是质数,因此当 i 不等于 0 且不等于 n 的时候,组合数阶乘公式中的 n 是没有办法被消掉的,就会被模成 0 ,因此这些项都是对答案没有贡献的。而 i=0 i=n 时,我们就分别可以得到 an bn ,定理得证。

有了这些定理,我们就可以嘿嘿嘿。

x2(a+ω)p+1(a+ω)p(a+ω)(ap+ωp)(a+ω)(aω)(a+ω)aap11(modp)a2ω2a2(a2n)n(modp)

然后 x 取相反数也是一个解。这时可能有人会问,我们得到的解会在 Fp2 域上的,但是我们要求的是 Fp 域的解,也就是说我们所谓的“虚部” ω 系数是否可能不为 0
其实我们不需要担心这个问题,由 拉格朗日定理,我们知道在任意一个模 p(pP) 的数域里面,任意一个多项式 f(x) 最多有 deg(f(x)) 个根( f(x)0(modp) 的解称为 f(x) Fp 下的根), deg 表示多项式的度数,即最大指数。由于 Fp2 是对 Fp 域的扩充, Fp 域的两根一定在 Fp2 内也有效,并且我们知道 x2n 在数域 Fp2 下的根有两个( x1,x2 ),那么 x1,x2 一定也是 Fp 域下的根,也就是“虚部”系数为 0
由此问题完美解决,算法时间复杂度貌似是 O(log2p) 的。

Code

我目前还没有去实现这个算法,我实现了会在这里贴上。

Problems

二次剩余的题目应该不怎么多。这个我会在博客里慢慢更新吧。
z 给我们讲了CodeChef上面一道丧心病狂的 BSGS (离散对数)和 Cipolla (二次剩余)连用的题目FN。

你可能感兴趣的:(杂文,阶和原根,快速幂,取模运算,二次剩余,OI)