二次剩余

简介

二次剩余是为了解决 (x^2equiv n (mode p)) ,已知 (n,p) ,求解 (x)

求解过程使用 (Cipolla) 算法来进行实现

定理

  • 定理 (1)(x^2 equiv n(mod p))中有 (frac{p−1}{2})(n) 能使方程有解。
  • 定理 (2): ((a+b)^p equiv a^p+b^p(mod p))
  • 定理 (3): (w^pequiv -w(mod p))
  • 定理 (4): (a^pequiv a(mod p))

勒让德符号

勒让德符号是为了判断一个书是否为 (p) 的二次剩余的一个有力工具,(p) 一定是要为奇质数。(frac{n}{p}) 是为了表示 (n) 为关于 (p) 的勒让德符号。其实就是判断 (n) 是否为 (p) 的二次剩余。

(frac{n}{p}) 结果为 (1) 时,(p) 不是 (n) 的倍数, (n)(p) 的二次剩余

(frac{n}{p}) 结果为 (-1) 时,(p) 不是 (n) 的倍数, (n)(p) 的非二次剩余

(frac{n}{p}) 结果为 (0) 时,(p)(n) 的倍数

进行判断 (n) 是否为 (p) 的二次剩余,可以使用欧拉定理进行解决。

欧拉判别准则

欧拉定理 (x^{varphi(p)} equiv 1(mod p))

因为 (p) 是奇质数,所以 (x^{p-1} equiv1(mod p))

因为 (x^{p-1} equiv1(mod p)) ,那么 (x^{frac{p-1}{2}} equiv ±1(mod p))

如果等于 (1) 就肯定开的了方, (-1) 则不能

if(pow(n,(p-1)/2,p)==p-1){
	printf("Hola!
");
	continue;
}

算法流程

题目

给出 (n)(p)
如何求出 (x^{frac{p-1}{2}} equiv 1(mod p))

找一个数 (a) ,使得勒让德符号为 (-1)

也就是求解 ((a^2-n)^{frac{p-1}{2}} = -1)

while(true){
	a=rand()%p;
	w=(a*a-n+p)% p;
	if(pow(w,(p-1)/2,p)==p-1)break;
}

时间复杂度异常低,平均每次查找 (a) 的期望是 (2),详细原因查看定理 (1)

建立一个复数域

对于复数,也就是 (i) ,满足 (i^2=-1)

之前已经得到一个 (a) ,定义 (w=sqrt{a^2-n})

使得现在的 (w^2=a^2-n)

可以用一个复数的式子 (a+bw) 来求解 (p) 的二次剩余。

struct Complex{
    ll x,y;
};
Complex mul(Complex a,Complex b,ll p,ll w){
    Complex c;
    c.x=(a.x*b.x%p+(a.y*b.y)%p*w%p)%p;
    c.y=(a.x*b.y%p+b.x*a.y%p)%p;
    return c;
}
Complex cpow(Complex a,ll n,ll p,ll w){
    Complex b;
    b.x=1,b.y=0;
    while(n){
        if(n&1)b=mul(b,a,p,w);
        n>>=1;
        a=mul(a,a,p,w);
    }
    return b;
}

得出答案

答案等于 ((a+bw)^{frac{p+1}{2}})

推导

问题 (x^2equiv n(mod p)) ,求解 (x)

(Cipolla) 算法 (xequiv(a+w)^{frac{p+1}{2}}(mod p))

[(a+w)^{frac{p+1}{2}}(mod p) \ equiv ((a+w)^{p+1})^{frac{1}{2}} (mod p) \ equiv ((a+w)^p(a+w))^{frac{1}{2}} (mod p) \ equiv ((a^p+w^p)(a+w))^{frac{1}{2}} (mod p) \ equiv ((a-w)(a+w))^{frac{1}{2}} (mod p) \ equiv (a^2-w^2)^{frac{1}{2}} (mod p) \ equiv (a^2-(a^2-n))^{frac{1}{2}} (mod p) \ equiv sqrt{n} (mod p) ]

Complex x;
x.x=a,x.y=1;
x=cpow(x,(p+1)/2,p,w);
ll x1=x.x,x2=p-x.x;
if(x1>x2)swap(x1,x2);
printf("%lld %lld
",x1,x2);

注意:当 (n=0) 时,最终结果只有 (0)

参考资料

https://blog.csdn.net/doyouseeman/article/details/52033204

https://kewth.github.io/2019/10/21/%E4%BA%8C%E6%AC%A1%E5%89%A9%E4%BD%99/

新赛季的开始
原文地址:https://www.cnblogs.com/VagrantAC/p/13280926.html