「学习笔记」二次剩余
说明:本文涉及变量除特殊说明外,全部属于整数集合。
前置芝士——二次剩余
二次剩余
当存在 \(x\) 使得 \(x^2\equiv a\pmod{p}\) ,那么我们称 \(a\) 是取模 \(p\) 的二次剩余(Quadratic residue)。
对于一个奇素数 \(p\) ,定义它的二次剩余集合为 \(F_p\) ,并且对于其中每一个数 \(n\) 满足 \(\exists x\in [0,p),x^x\equiv n\pmod{p}\) 。
二次剩余的个数
对于前面定义的集合,有 \(\mid F_p \mid=\frac{p+1}{2}\) ,证明如下:
令 \(u^2\equiv v^2\equiv n\pmod{p},u\neq v\) ,那么
显然,若 \(p\mid (u-v)\) ,因为 \(p\) 为奇素数,那么 \(u-v=p\) ,但这是不可能满足的。
即一定有 \(p\nmid (u-v)\) ,那么就有 \(p\mid (u+v)\) ,同理, \(u+v=p\) 。
即在 \(u,v\in [0,p)\) 的范围中,除 \(0\) 以外,其他的数两两对应。
那么个数就是 \(\frac{p-1}{2}+1=\frac{p+1}{2}\) ,证毕。
欧拉准则
用来判定一个非零数是否是二次剩余。
对于一个 \(d\) 满足 \((d,p)=1,d>0\) ,那么一定满足
证明:
根据费马小定理,一定有
若 \(\exists x,x^2\equiv d\pmod p\) ,那么就有 \(d^{\frac{p-1}{2}}\equiv x^{p-1}\pmod p\) 。
那么,就有满足 \(d\in F_p\) 时,有 \(d^{\frac{p-1}{2}}\equiv 1\pmod{p}\) 。
过程
现在我们要求一个 \(x\) 满足
用以下步骤可求得 \(x\) 。
- 随机一个 \(t\) ,满足 \(t^2-a\notin F_p\) 。
- 令 \(\omega =\sqrt{t^2-a}\) ,则 \(x=(t+\omega)^{\frac{p+1}{2}}\)
证明过程需要几个小定理...
定理一
- 内容:
- 证明:
当 \(i\neq 0\) 且 \(i\neq p\) ,满足 \(\binom{p}{i}\equiv 0\pmod p\) 。
定理二
- 内容:
- 证明:
因为 \(t^2-a\notin F_p\) ,所以满足
定理三
- 内容:
由 \((1)、(2)\) 显然。
证明
由前面的定理可知
关于 ω
方程 \(x^2-a=0\) 在任何域中都有两个根(由勒让德定理),并且并且我们前面得到了这两个根都在模 \(p\) 的剩余系中,所以没有 \(\omega\) 。
代码实现
代码处理的时候,只需要记录公式中 \(a+b\omega\) 的两个系数 \(a、b\) 即可。
struct Z{
uint x;
Z(const uint _x=0):x(_x){}
inline Z operator +(const Z &rhs)const{return x+rhs.x<MOD?x+rhs.x:x+rhs.x-MOD;}
inline Z operator -(const Z &rhs)const{return x<rhs.x?x-rhs.x+MOD:x-rhs.x;}
inline Z operator -()const{return x?MOD-x:0;}
inline Z operator *(const Z &rhs)const{return (ull)x*rhs.x%MOD;}
inline Z operator +=(const Z &rhs){return x=x+rhs.x<MOD?x+rhs.x:x+rhs.x-MOD,*this;}
inline Z operator -=(const Z &rhs){return x=x<rhs.x?x-rhs.x+MOD:x-rhs.x,*this;}
inline Z operator *=(const Z &rhs){return x=(ull)x*rhs.x%MOD,*this;}
inline bool operator ==(const Z &rhs){return x==rhs.x;}
};
#define pzz pair<Z,Z>
inline pzz Mul(pzz x,pzz y,Z f){
//计算 a+bω 部分的 pzz 的乘法
return mp(x.ft*y.ft+x.sd*y.sd*f,x.ft*y.sd+x.sd*y.ft);
}
inline Z Quadratic_residue(Z a){
//常数在模意义下的开根
if(a.x<=1)return a.x;
//使用欧拉定律判断有无解
if(qkpow(a,(MOD-1)>>1).x!=1)return -1;
Z x,f;
//找到一个 x 使得 x^2 - a 不是二次剩余
do x=(((ull)rand()<<15)^rand())%(a.x-1)+1;
while(qkpow(f=x*x-a,(MOD-1)>>1)==Z(1));
//初始变量
pzz ans=mp(1,0),t=mp(x,1);
//类似于快速幂
for(uint i=(MOD+1)>>1;i>0;i>>=1,t=Mul(t,t,f))if(i&1)ans=Mul(ans,t,f);
//返回较小根
return Min(ans.ft.x,MOD-ans.ft.x);
}