ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

二次剩余 Cipolla 算法浅析

2022-07-05 16:02:47  阅读:216  来源: 互联网

标签:x1 return pmod over 算法 x0 Cipolla 浅析 LL


参考资料

求解

\[x^2=n \pmod p \]

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

判定是否存在二次剩余

设 \(n=g^a,x=g^b\),由于原根环的长度为 \(p-1\) (是个偶数),
列出方程 \(2b = a \pmod {p-1}\),根据贝祖定理,当且仅当 \(\gcd(p-1,2)=2 \mid a\) 时有解。
因此

  • 在 \(a\) 为偶数时有解 \(g^{ a\over 2}\) 和 \(-g^{ a\over 2}\)。
  • 在 \(a\) 为奇数时无解。

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

  • 在 \(a\) 为偶数时,\(n^{p-1 \over 2}=g^{a(p-1) \over 2}=(g^{a \over2})^{p-1}=1 \pmod p\)
  • 在 \(a\) 为奇数时,\(n^{p-1 \over 2}=g^{a(p-1) \over 2}\),由于 ${a(p-1)\over 2} \ne 0 \pmod {p-1} $,因此 \(n^{p-1 \over 2} \ne 1\) 。但是 \((n^{p-1 \over 2})^2=n^{p-1}=1 \pmod p\),所以 \(n^{p-1 \over 2}=-1\)。

因此 有无解等价于 \(n^{p-1 \over 2}\) 是否为 \(1\)。

上述证明过程的一些推论

  • 若有解,必有两个 ,因为 \(g^{ a\over 2}\) 和 \(-g^{ a\over 2}\) 的奇偶性不同。同时不会有更多个,因为 \(2b = a \pmod {p-1}\) 的步长为 \({p-1 \over \gcd(2,p-1)}={p-1 \over 2}\) 加两次又回到第一个点了。
  • 在 \(\bmod \: p\) 意义下有 \({p-1\over 2}\) 个二次剩余,\({p-1\over 2}\) 个二次非剩余。(考虑 \(p-1\) 是偶数,\([1,p-1]\) 的数中有几个偶数和奇数)。

二次剩余的求解

先随机出一个 \(a\) ,使 \(a^2-n\) 为二次非剩余。
扩域,假设存在一个 \(w\) 使得 \(w^2=a^2-n \pmod p\)。
则 \(n=(a+w)(a-w)\) 。

  • 引理1:\(w^p=-w\)(证明:\(w^p=(w^2)^{p-1 \over2}w=w(a^2-n)^{p-1 \over 2}=-w\))
  • 引理2:\((a+w)^p=a^p+w^p\) 证明:\(j \in [1,p-1],{p \choose j}|p\).

\[(a+w)^{p+1}=(a+w)^p(a+w)=(a^p+w^p)(a+w)=(a^{p-1}a-w)(a+w)=(a-w)(a+w)=n \]

因此 \((a+w)^{p+1 \over 2}\) 为一个解。
容易得出另一个解为 \(-(a+w)^{p+1 \over 2}\)

Code

#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,原根之类解更多方程。

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

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;
}

标签:x1,return,pmod,over,算法,x0,Cipolla,浅析,LL
来源: https://www.cnblogs.com/cjl-world/p/16446774.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有