二次剩余小记

command_block

2019-08-19 13:22:43

Personal

**P.S** 本文只探讨模数$p$是**奇质数**的情况。 ## 目标/定义 求解 $\large{x^2=c(mod\ p)}$ 这个方程组。 如果方程有解,则称$c$是模$p$的**二次剩余**,否则称作二次非剩余。 (下面默认在模$p$的剩余系下讨论) ## 欧拉判别法 给定$c,p$,如何判定 $x^2=c$ 是否有解呢? $\color{blue}\text{结论:}$ $c^{\large{\frac{p-1}{2}}}=\begin{cases}\ \ \ 1\rightarrow\text{有解}\\ -1\rightarrow\text{无解}\end{cases}$ $\color{blue}\text{证明:}$ - 引理$\color{blue}1.1$ : $c^{\large{\frac{p-1}{2}}}=±1$ 由费马小定理得$(c^{\large{\frac{p-1}{2}}})^2=c^{p-1}=1$,可得$c^{\large{\frac{p-1}{2}}}=±1$ - 引理$\color{blue}1.2$ $c^{\large{\frac{p-1}{2}}}=-1 \Rightarrow c$不是二次剩余 采用反证法,假设有$x^2=c$,可得$c^{\large{\frac{p-1}{2}}}=x^{p-1}=-1$ 与费马小定理矛盾,原命题得证。 - 引理$\color{blue}1.3$ $c^{\large{\frac{p-1}{2}}}=-1 \Leftarrow c$不是二次剩余 假设有$x^2=c$,但是$x$不是同余系里面的数,可以视为虚数,只满足$x^2=c$这一条性质。 由于$x$不是同余系内的数,**必定**不满足费马小定理,可得$x^{p-1}≠1$,那么只能是$-1$了。 (费马小定理对且只对同余系生效) 综上三个引理可以逻辑推导出欧拉判别法,证毕。 ## 二次剩余的个数 $\color{blue}\text{结论:}$ 模$p$下的二次剩余恰有$\dfrac{p-1}{2}$个。 - 引理 : $c^2=(p-c)^2$ 显然成立,由此可得,如果$x^2=c$有解,则必然有两解。 $\color{blue}\text{证明:}$ 任选两个数$x,y(x≠y)$,且$x^2=y^2$ 那么$(x+y)(x-y)=0$,即$p|(x+y)(x-y)$, 显然$p|(x-y)$不成立,那么$p|(x+y)$,即$x+y=0$。 那么,对于一个$x$,和它平方相同的有且仅有另外一个$y$。 总共有$\dfrac{p-1}{2}$个不同的平方,那么二次剩余,二次非剩余各有$\dfrac{p-1}{2}$个。 ## Cipolla算法 现在真正来求解$x^2=c(mod\ p)$ 首先判定方程是否无解(如果$c=0$则输出0) 如果有解,我们任意找一个$a$,使得$a^2-c$是**二次非剩余**。 方法:不断随机然后判定。根据上文内容,期望随机次数$2$次。 设$w^2=(a^2-c)$,注意$w$不是同余系里面的数,可以理解为虚数,只有$w^2=(a^2-c)$这一条性质。 我们扩系,把每个数变成$a+bw$的形式,重载运算。容易证明扩系之后仍然是环。 > **P.S** 设$s=w^2=(a^2-c)$ > $(x_1+y_1w)*(x_2+y_2w)=(x_1x_2+y_1y_2s)+(x_1y_2+x_2y_1)w$ 那么$c=(a+w)^{p+1}$,所以$x=(a+w)^{\frac{p+1}{2}}$ - 引理$\color{blue}3.1$ $(a+b)^p=a^p+b^p$ 二项式展开可得 : $(a+b)^p=\sum\limits_{i=0}^p\dbinom{i}{p}a^{i}b^{p-i}$ 由卢卡斯定理 : $\dbinom{i}{p}=\dbinom{i/p}{p/p}\dbinom{i\%p}{p\%p}=\dbinom{i/p}{1}\dbinom{i\%p}{0}$ 这个式子只在$i=0$或者$p$的时候值为1,否则为0. 所以$(a+b)^p=a^p+b^p$ - 引理$\color{blue}3.2$ $w^p=-w$ $w^p=w^{p-1}w=(a^2-c)^{\large{\frac{p-1}{2}}}w$ 由欧拉判别法,$(a^2-c)^{\large{\frac{p-1}{2}}}=-1$,证毕。 那么 : $(a+w)^{p+1}=(a^p+w^p)(a+w)=(a+w)(a-w)$ $=a^2-w^2=a^2-a^2+c=c$ 正确性得证。 [P5491 【模板】二次剩余](https://www.luogu.org/problem/P5491) ```cpp #include<algorithm> #include<cstdio> #define ll long long using namespace std; int mod,c; ll powM(ll a,int t) { ll ans=1; while(t){ if (t&1)ans=ans*a%mod; a=a*a%mod; t>>=1; }return ans; } ll sav; struct Mcp { ll x,y; Mcp operator * (Mcp const& B) const {return (Mcp){(x*B.x+y*B.y%mod*sav)%mod,(x*B.y+y*B.x)%mod};} }; Mcp powM(Mcp a,int t) { Mcp ans=(Mcp){1,0}; while(t){ if (t&1)ans=ans*a; a=a*a; t>>=1; }return ans; } void solve() { scanf("%d%d",&c,&mod); if (c==0) {puts("0");return ;} if (powM(c,(mod-1)/2)==mod-1) {puts("Hola!");return ;} int a; while(1){ a=(rand()%(mod-1)+mod)%(mod-1)+1; sav=(1ll*a*a-c+mod)%mod; if (powM(sav,(mod-1)/2)==mod-1){ Mcp W=(Mcp){a,1}; W=powM(W,(mod+1)/2); ll x1=W.x,x2=mod-W.x; if (x1>x2)swap(x1,x2); printf("%lld %lld\n",x1,x2); break; } } } int main() { int T; scanf("%d",&T); while(T--)solve(); return 0; } ```