二次剩余

ppp是奇素数。所有的运算都是在群Zp∗Z_{p}^{*}Zp∗​中的运算。方程x2=a≠0x^2=a \neq 0x2=a̸​=0问是否有解,以及解是什么?若有解,aaa就是模ppp的二次剩余;若无解,则aaa就是模ppp的非二次剩余。

  1. a=0a=0a=0,显然只有唯一解x=0x=0x=0.

  2. a≠0a\neq 0a̸​=0,有解等价于ap−12=1a^{\frac{p-1}{2}}=1a2p−1​=1;无解等价于ap−12=−1a^{\frac{p-1}{2}}=-1a2p−1​=−1.

群Zp∗Z_{p}^{*}Zp∗​恰好有一半的元素是二次剩余,一半的元素不是二次剩余。当元素aaa是二次剩余是,解有且只有两个x0,x1x_0,x_1x0​,x1​,且x0=−x1x_0=-x_1x0​=−x1​,即解x=±cx=\pm cx=±c

因此,验证aaa是否是二次剩余可以用快速模幂,复杂度O(log⁡2p)O(\log_2{p})O(log2​p).

对于二次剩余aaa,求解x使用[Cipolla]{.underline}(洋葱? 奇波拉?)算法。

Cipolla(洋葱?)算法

这是一个随机性算法,复杂度是O(log⁡2p)O(\log_2{p})O(log2​p)

这个算法是在域Fp2F_{p^2}Fp2​上进行运算的,在这个域上做乘法、幂运算,然后解的那个表达式算出来之后,一定是属于域FpF_{p}Fp​的,Fp2F_{p^2}Fp2​是FpF_{p}Fp​的扩充。

  1. 使用随机的方法,找到一个满足bbb满足b2−ab^2-ab2−a不是二次剩余。需要检验b2−ab^2-ab2−a是不是二次剩余的期望次数是222.每次检验是O(log⁡2p)O(\log_2{p})O(log2​p).

  2. 定义域Fp2F_{p^2}Fp2​上的*“虚部单位”*为ω\omegaω,其中Fp2=a+bω∣a,b∈FpF_{p^2}={a+b\omega| a,b \in F_p}Fp2​=a+bω∣a,b∈Fp​,且ω2=b2−a\omega^2=b^2-aω2=b2−a.

  3. x2=ax^2=ax2=a的其中一个**解是x=(b+ω)p+12.x=(b+\omega)^{\frac{p+1}{2}}.x=(b+ω)2p+1​.*注意,虽然运算是Fp2F_{p^2}Fp2​上的,但是右边的那个式子算出来的结果刚好是"虚部"*为0的元素。原因是x2=a(x∈Fp)x^2=a \quad (x \in F_p)x2=a(x∈Fp​)与x2=(xa+xbω)2=a+0ω(x∈Fp2,xa,xb∈Fp)x^2=(x_a+x_b\omega)^2=a+0\omega \quad (x \in F_{p^2},x_a,x_b \in F_p)x2=(xa​+xb​ω)2=a+0ω(x∈Fp2​,xa​,xb​∈Fp​)这两个方程都有且仅有两个解。而前面方程的解显然是后面两个方程的解,所以前面方程的解。所以前面这个方程和后面这个方程的解是完全一样的。而对于后面这个方程x=(b+ω)p+12x=(b+\omega)^{\frac{p+1}{2}}x=(b+ω)2p+1​代入后面的方程去验证(为了计算简洁,先证明了一些性质),会发现它的确是解,于是这个式子就是一开始方程的解。

证明

判别准则的证明

a≠0a\neq 0a̸​=0,有解等价于ap−12=1a^{\frac{p-1}{2}}=1a2p−1​=1;无解等价于ap−12=−1a^{\frac{p-1}{2}}=-1a2p−1​=−1.

以上这个命题的证明,主要分为——

这个的证明主要是需要用到Zp∗Z_p^*Zp∗​是个循环群,每个元素都可以表示成生成元的幂次的形式。

首先,明确一点,因为∀a∈Zp∗,ap−1=1\forall a \in Z_p^*,a^{p-1}=1∀a∈Zp∗​,ap−1=1,再运用根据二次探测定理,容易得到ap−12a^{\frac{p-1}{2}}a2p−1​取值只能是±1\pm1±1,即111或p−1p-1p−1.

  • 有解,即aaa是二次剩余,则ap−12a^{\frac{p-1}{2}}a2p−1​算出来是,这个将aaa换成x2x^2x2,再根据费马小定理易得。
  • 无解,即aaa不是二次剩余,容易推出aaa表示成生成元bbb的幂次的形式(bkb^kbk)中的kkk只能是奇数(否则,取x=bk2x=b^{\frac{k}{2}}x=b2k​就可以导出x2=ax^2=ax2=a)。将kkk表示成2u+12u+12u+1的形式,然后将a=b2u+1a=b^{2u+1}a=b2u+1代入ap−12a^{\frac{p-1}{2}}a2p−1​容易得到ap−12=bp−12a^{\frac{p-1}{2}}=b^{\frac{p-1}{2}}a2p−1​=b2p−1​.因为bbb是生成元,所以阶是p−1p-1p−1,指数小于p−1p-1p−1时,算出来都不是单位元111.所以bp−12=−1b^{\frac{p-1}{2}}=-1b2p−1​=−1(别忘了只能取±1\pm1±1).

    虽然以上每一点都只进行了单向推导,但是以上两点综合起来,就说明了“a≠0a\neq 0a̸​=0,有解等价于ap−12=1a^{\frac{p-1}{2}}=1a2p−1​=1;无解等价于ap−12=−1a^{\frac{p-1}{2}}=-1a2p−1​=−1.”

解的证明

算法构造的解,运算是在Fp2=x∣x=a+bω∧a,b∈FpF_{p^2}={x|x=a+b\omega \wedge a,b \in F_p}Fp2​=x∣x=a+bω∧a,b∈Fp​,其中ω2=b2−a\omega^2=b^2-aω2=b2−a.

对于&lt;Fp2,+,∗&gt;&lt;F_{p^2},+,*&gt;<Fp2​,+,∗>

并且定义了(a1+b1ω)+(a2+b2ω)=(a1+b1)+(b1+b2)ω(a_1+b_1\omega)+(a_2+b_2\omega)=(a_1+b_1)+(b_1+b_2)\omega(a1​+b1​ω)+(a2​+b2​ω)=(a1​+b1​)+(b1​+b2​)ω,

(a1+b1ω)×(a2+b2ω)=(a1b1+b1b2ω2)+(b1a2+a1b2)ω(a_1+b_1\omega) \times (a_2+b_2\omega)=(a_1b_1+b_1b_2\omega^2)+(b_1a_2+a_1b_2)\omega(a1​+b1​ω)×(a2​+b2​ω)=(a1​b1​+b1​b2​ω2)+(b1​a2​+a1​b2​)ω

定义完了之后,可以通过基本的代数知识,证明&lt;Fp2,+,∗&gt;&lt;F_{p^2},+,*&gt;<Fp2​,+,∗>是一个域。

原方程是在x2=ax^2=ax2=a在FpF_pFp​域内,而将方程的研究域改为Fp2F_{p^2}Fp2​之后。

无论是原域还是新域,解的个数至多只有两个。(这个是拉格朗日定理得出来的,暂时不懂朗格朗日定理,搁置,记结论)。因此,a是二次剩余的情况下,原方程有解x=±cx=\pm cx=±c,这两个解显然是新域下的解。又因为新域下没有更多解,所以新域下的解就是原域下的解。

因此,证明就只剩下验证x=(b+ω)p+12x=(b+\omega)^{\frac{p+1}{2}}x=(b+ω)2p+1​符合方程x2=ax^2=ax2=a即可。

直接代入计算就好了。只是由于为了计算比较简洁,有条理,不会算不下去,先给出了不少性质(定理)。这个别的博客基本都有,就不复言了。

下面为模板:

域Fp2F_{p^2}Fp2​乘法与幂运算模板

应当放在**mod_sys(见快速乘幂)**的模板前面。

	// 二次剩余模板,注意,各个函数都假设p^2即mod^2不会爆ll
// 域F_p的拓展域F_{p^2}
struct F_p2_node{ll a,b;}; // F_p2_node所有的运算都应该通过F_p2_sys来管理调用。
// 预设所有传入参数都是合法的。
struct F_p2_sys{
ll p,w2;
typedef F_p2_node nd;
nd mlt(const nd&x, const nd&y) const {
nd ans;
//(x.a+x.bw)(y.a+y.bw)
ans.a = (x.a*y.a%p+x.b*y.b%p*w2%p)%p;
ans.b = (x.b*y.a%p+x.a*y.b%p)%p;
return ans;
}
// pre n>=0 非递归版 不可改成引用!
nd pow(nd a, ll n) const {
if (n == 0) {return nd{1,0};}
// 始终维持要求的数可以表示为(a)^n*t
nd t{1,0};
while (n > 1)
{
if (n&1) t = mlt(t,a);
n >>= 1; a = mlt(a,a);
}
return mlt(t,a);
}
};

Cipolla洋葱算法实现模板

需要使用先用快速乘幂的模板中的mod_sys,实际上,这个模板只是给那个mod_sys增加了成员函数。

struct mod_sys{
// template code from 快速乘幂 见前面章节
some code.... // 预设a \not\equiv 0 (mod mod) 返回a是否是二次剩余
// 预设mod是奇素数
// 预设p^2不会爆long long,使用pow 若爆则改用pow_v2或者__int128
bool is_quadratic_residue(ll a) {
return 1 == pow(a,mod-1>>1);
} // 解方程x^2 = a (mod mod) p = mod 是奇质数
// 返回是否有解。如果有x0,x1(x0<=x1)存储解 仅解是0的时候取等号
// 洋葱算法。
// 预设p^2不会爆long long,使用pow 若爆则改用pow_v2或者__int128
bool sqrt(ll a,ll& x0, ll& x1) { // 需要一个随机数生成器
a = to_std(a);
if (a == 0) {x0 = x1 = 0; return true;}
if (!is_quadratic_residue(a)) return false;
uniform_int_distribution<> dis(1, mod-1);
ll b,w2;
while(true) {
b = dis(gen);
w2 = to_std((b*b)%mod-a);
if (!is_quadratic_residue(w2)) break;
}
// x = (b+w)^{(p+1)/2}
F_p2_sys fp2{mod,w2}; // p,w2
F_p2_node t{b,1}; // a,b(means a+bw)
auto x = fp2.pow(t,mod+1>>1);
x0 = to_std(x.a); // assert(x.b==0);
x1 = mod-x.a;
if (x0 > x1) swap(x0,x1);
return true;
}
};

二次剩余的判定及Cipolla算法的更多相关文章

  1. 二次剩余Cipolla算法学习笔记

    对于同余式 \[x^2 \equiv n \pmod p\] 若对于给定的\(n, P\),存在\(x\)满足上面的式子,则乘\(n\)在模\(p\)意义下是二次剩余,否则为非二次剩余 我们需要计算的 ...

  2. 二次剩余定理及Cipolla算法入门到自闭

    二次剩余定义: 在维基百科中,是这样说的:如果q等于一个数的平方模 n,则q为模 n 意义下的二次剩余.例如:x2≡n(mod p).否则,则q为模n意义下的二次非剩余. Cipolla算法:一个解决 ...

  3. Cipolla算法学习小记

    转自:http://blog.csdn.net/doyouseeman/article/details/52033204 简介 Cipolla算法是解决二次剩余强有力的工具,一个脑洞大开的算法. 认真 ...

  4. Cipolla算法学习笔记

    学习了一下1个$\log$的二次剩余.然后来水一篇博客. 当$p$为奇素数的时候,并且$(n, p) \equiv 1 \pmod{p}$,用Cipolla算法求出$x^2 \equiv n \pmo ...

  5. 二次剩余 Cipolla算法

    欧拉准则 \(a\)是\(p\)的二次剩余等价于\(a^{\frac{p-1}{2}}\equiv 1\pmod p\),\(a\)不是\(p\)的二次剩余等价于\(a^{\frac{p-1}{2}} ...

  6. 【模板】【数论】二次剩余Cipolla算法,离散对数BSGS 算法

    Cipolla LL ksm(LL k,LL n) { LL s=1; for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo; return s; } n ...

  7. HDU 2444 The Accomodation of Students (偶图判定,匈牙利算法)

    题意: 有一堆的学生关系,要将他们先分成两个组,同组的人都不互不认识,如果不能分2组,输出No.若能,则继续.在两组中挑两个认识的人(每组各1人)到一个双人房.输出需要多少个双人房? 思路: 先判定是 ...

  8. Java虚拟机判定对象存活算法

    1.引用计数算法 描述:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1:当引用失效时,计数器值就减1:任何时刻计数器值为0的对象就是不可能再被使用的. 特点:实现简单,判定效率高. ...

  9. 梅森素数 判定总结 - Lucas-Lehmer算法 & Miller-rabin算法

    梅森素数 定义: if m是一个正整数 and 2^m-1是一个素数 then m是素数 if m是一个正整数 and m是一个素数 then M(m)=2^m-1被称为第m个梅森数 if p是一个素 ...

随机推荐

  1. Docker | Mac 通过 Docker 安装 Oracle

    Docker | Mac 通过 Docker 安装 Oracle 前言: Oracle 10g 以后就不支持 Mac 版本,因此 Mac 用户需要安装的话可以通过虚拟机或者 Docker 1.在 do ...

  2. Gloang Swagger

    功能 自动化生产接口文档 安装 # 安装swaggo get -u github.com/swaggo/swag/cmd/swag # 安装 gin-swagger go get -u github. ...

  3. JDK的下载及安装教程图解(超详细哦~)

    一.本人电脑系统介绍及JDK下载途径 1.先说明一下我的电脑为win10系统,64位操作系统~ 2.我选择下载的JDK版本为1.8版本.给大家来两个下载渠道,方便大家的下载~ JDK官网:https: ...

  4. 啥?你想diy一个智能音箱,来吧

    没错,这是智zhang语音助手 本系统基于自美系统二次开发,添加连接EMQ服务器,语音远程控制LED(Nodemcu),当然也可以扩展控制更多的设备,只需要将下位机设备连接到EMQ服务器即可. 由于使 ...

  5. Oracle操作语句--增加/删除

    1.删除1980年雇员的雇员信息: delete  from myemp where     hiredate between to_date('1980-1-1','yyyy-mm-dd') and ...

  6. 视觉slam十四讲ch6曲线拟合 代码注释(笔记版)

    // ceres 版本 1 #include <opencv2/core/core.hpp> #include <ceres/ceres.h> #include <chr ...

  7. Navicat Premium 12(破解版免安装)

    获取安装包解压至任意位置 切勿更新!!! 切勿更新!!! 切勿更新!!! 扫下方二维码关注公众号回复:navicat12即可获取

  8. 【笔记】最短路——SPFA算法

    ##算法功能 找最短路(最长路?) ##算法思想 用一个节点k更新节点i到节点j的最短路 ##邻接链表存储 基础而高效的图的存储方式 存的是单向边(无向边可以看成两条有向边) ##实现 维护节点i到源 ...

  9. Window10和Ubuntu 18.04双系统安装的引导问题解决

    作为码农 首先,建议了解下grub2的启动顺序和逻辑.可以参考这篇文章,grub.cfg详解. 从执行顺序倒推,如下如果全部执行成功,则会进入grub的启动菜单:如果最后一步,没有找到grub.cfg ...

  10. DeBug Python神级工具PySnooper

    安装 pip3 install pysnooper import pysnooper @pysnooper.snoop() def number_to_bits(number): if number: ...