二次剩余 Cipolla 算法浅析

参考资料

求解

x2=n(modp)

仅介绍模数 p 为奇素数的解法,也就是 Cipolla 算法。

判定是否存在二次剩余

n=ga,x=gb,由于原根环的长度为 p1 (是个偶数),
列出方程 2b=a(modp1),根据贝祖定理,当且仅当 gcd(p1,2)=2a 时有解。
因此

  • a 为偶数时有解 ga2ga2
  • a 为奇数时无解。

用原根求解较慢,尝试寻找等价条件。

  • a 为偶数时,np12=ga(p1)2=(ga2)p1=1(modp)
  • a 为奇数时,np12=ga(p1)2,由于 a(p1)20(modp1),因此 np121 。但是 (np12)2=np1=1(modp),所以 np12=1

因此 有无解等价于 np12 是否为 1

上述证明过程的一些推论

  • 若有解,必有两个 ,因为 ga2ga2 的奇偶性不同。同时不会有更多个,因为 2b=a(modp1) 的步长为 p1gcd(2,p1)=p12 加两次又回到第一个点了。
  • modp 意义下有 p12 个二次剩余,p12 个二次非剩余。(考虑 p1 是偶数,[1,p1] 的数中有几个偶数和奇数)。

二次剩余的求解

先随机出一个 a ,使 a2n 为二次非剩余。
扩域,假设存在一个 w 使得 w2=a2n(modp)
n=(a+w)(aw)

  • 引理1:wp=w(证明:wp=(w2)p12w=w(a2n)p12=w
  • 引理2:(a+w)p=ap+wp 证明:j[1,p1],(pj)|p.

(a+w)p+1=(a+w)p(a+w)=(ap+wp)(a+w)=(ap1aw)(a+w)=(aw)(a+w)=n

因此 (a+w)p+12 为一个解。
容易得出另一个解为 (a+w)p+12

Code

copy
#include<ctime> #include<cstdio> #include<cstdlib> #include<iostream> using namespace std; typedef long long LL; typedef pair<LL,LL> PLL; LL power(LL x,LL k,LL MOD) { LL res=1; x=x%MOD; while(k) { if(k&1) res=res*x%MOD; x=x*x%MOD; k>>=1; } return res%MOD; } PLL mul(PLL a,PLL b,LL IOI,LL p) { return PLL((a.first*b.first%p+a.second*b.second%p*IOI%p)%p,(a.second*b.first%p+a.first*b.second%p)%p); } bool residue(LL n,LL p,LL& x0,LL& x1) { if(n==0) return (x0=x1=0,true); // 注意这个特判 if(power(n,(p-1)>>1,p)!=1) return false; LL a=rand()%p; while(!a || power(a*a-n+p,(p-1)>>1,p)==1) a=rand()%p; LL IOI=(a*a-n+p)%p; LL k=(p+1)>>1; PLL res(1,0),x(a,1); while(k) { if(k&1) res=mul(res,x,IOI,p); x=mul(x,x,IOI,p); k>>=1; } x0=res.first; x1=p-x0; if(x0>x1) swap(x0,x1); return true; } int T; LL n,p; int main() { srand(time(0)); cin>>T; while(T--) { cin>>n>>p; LL x0,x1; if(!residue(n,p,x0,x1)) puts("Hola!"); else printf("%lld %lld\n",x0,x1); } return 0; }

应用

本身可以解一元二次方程
也可以配合 exgcd,BSGS,原根之类解更多方程。

求解 一元二次方程 在模意义下的根。

copy
bool solve(LL a,LL b,LL c,LL p,LL& x0,LL& x1) { a=(a%p+p)%p; b=(b%p+p)%p; c=(c%p+p)%p; LL d=(b*b-4*a*c%P+P)%P; if(!residue(d,p,x0,x1)) return false; d=x0; x0=(-b+d+p)*inv(a+a,p)%p; x1=(-b-d+2*p)*inv(a+a,p)%p; return true; }
posted @   cjlworld  阅读(130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起