专栏文章

Cornacchia 算法 & P2063 二平方和定理

P2063题解参与者 5已保存评论 5

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
5 条
当前快照
1 份
快照标识符
@minyj542
此快照首次捕获于
2025/12/02 10:26
3 个月前
此快照最后确认于
2025/12/02 10:26
3 个月前
查看原文
闲话:在学校不但睡不好而且甚至睡不着,睡眠时间还被新来的校长砍了,而且我没得打 WA2,我甚至还没打完 coda 篇任意一条线路,周日没有休息,恐怕要初赛后才能打。
闲话:很难说这是一个特别的算法,还是一个欧几里得辗转相除的 trick,不过我似乎没有看到一个合适的中文介绍。不论如何,它很方便地解决了我在模拟赛中遇到的问题。

一道模拟赛题

假设我们要解决这样一个问题。
给定一个正整数 2n10182\le n\le 10^{18},构造一组解 (a,b)(a,b) 满足 a,ba,b 均为非负整数且 a2+b2=na^2+b^2=n,或报告无解。
本题有一些和 Cornacchia 算法完全无关的做法,复杂度从四次根号到几个 log\log 都有,但是相比之下 Cornacchia 算法可能更为通用(以及优美)。
对于这个问题,如果使用该算法,主要瓶颈在质因数分解以及二次剩余上。
首先是一些简单的推导。
“高斯整数”?
以防有人像我一样不知道什么是高斯整数。
高斯整数是形如 a+bia + bi 的复数,更准确地说,这篇文章中涉及的复数都是高斯整数。
大家知道,复数相乘时模长相乘。将问题转化一下,考虑去构造一个复数序列 w1kw_{1\cdots k} 使得 i=1kwi2=n|\prod_{i=1}^k w_i|^2=n,当然每个复数的实部和虚部都是非负整数。然后就只需要输出 i=1kwi\prod_{i=1}^k w_i 的实部和虚部就可以了,记得取绝对值。
当然,上面的讨论看起来一点信息量都没有。所以先质因数分解,设 n=i=1cntpicin=\prod_{i=1}^{cnt} p_i^{c_i},对于每个 pip_i 分别构造。
  1. pi=2p_i=2
    v=1+iv=1+\mathrm{i} 易得 v2=2|v|^2=2,那么往 ww 序列里插入 cic_i1+i1+\mathrm{i},即可让 w2|\prod w|^2 的值乘上 2ci2^{c_i}
  2. pi3(mod4)p_i\equiv 3 \pmod 4
    • 对于 ci0(mod2)c_i\equiv 0 \pmod 2,往 ww 序列里插入 ci/2c_i/2pip_i(注意是高斯整数 pip_i,更精确地说是 pi+0ip_i+0\mathrm{i})即可,每个 pip_iw2|\prod w|^2 的贡献显然是 pi2p_i^2
    • 否则报告无解。
    为什么无解?
    学过小学奥数的朋友都知道,完全平方数模 440011
    没学过也不用担心,学过抽象代数的朋友都知道,整数中模 4433 的素数 pp 在高斯域中是惯性的,(p)(p) 仍然是素理想。
    如果都没学过,打表找规律也不失为一个好办法。
    你问我初等方法?因为 pp 是奇数,若 pp 是完全平方数,则 n=pn=\sqrt p 是奇数。设 n=2k+1(kN)n=2k+1(k\in \mathbb N),有 n2=4k2+4k+11(mod4)n^2=4k^2+4k+1\equiv 1 \pmod 4
  3. pi1(mod4)p_i\equiv 1 \pmod 4
    我断言,我们可以使用 Cornacchia 算法在 O(log2V)\mathcal O(\log^2 V) 时间内构造一组 (ai,bi)(a_i,b_i) 满足 ai2+bi2=pia_i^2+b_i^2=p_i,然后往 ww 里面插入 cic_iai+ibia_i+\mathrm{i}b_i 即可。根据费马平方和定理,存在满足条件的解 (ai,bi)(a_i,b_i)
当然了,实现的时候肯定要用快速幂把相等的复数先积起来,然后把所有东西乘起来。
它的正确性由过程给出。复杂度瓶颈,如前所述,在于写出高效的质因数分解和二次剩余。

P2063 二平方和定理

给定一个正整数 2n10182\le n\le 10^{18},求出所有非负整数数对 (a,b)(a,b) 满足 a2+b2=na^2+b^2=n
相比于上面那个题,这次我们需要构造所有的解。
可以发现,刚刚关于高斯整数的模型似乎仍然是适用的。
由唯一分解定理可以得到,最终仍旧得先质因数分解到每个质因子,再全部乘起来。
我们试着进一步分析看看,对于每个质数有多少种对应到高斯整数的方法,来试图遍历到所有解。
  1. pi=2p_i=2
    仍旧仅有 1+i1+\mathrm{i} 一种可能,在实部和虚部分别枚举 0,1,20,1,2 即可得到。
  2. pi3(mod4)p_i\equiv 3 \pmod 4
    与刚刚的分析相同,必须得把 pip_i 两两配对来产生若干个 pi2p_i^2 的贡献。用同样的手法可以证明,只有 pi+0ip_i+0\mathrm i0+pii0+p_i\mathrm i 两种可能的情况。
  3. pi1(mod4)p_i\equiv 1 \pmod 4
    类似的只有两组本质相同的解 (ai,bi)(a_i,b_i)(bi,ai)(b_i,a_i)(容易注意到 aibia_i \ne b_i)。
    引理,等一会还要用到
    (x,y)(x,y) 是方程 x2+dy2=px^2 + d\cdot y^2 = p 的一组非负整数解,且 y≢0(modp)y \not \equiv 0 \pmod p,则 ±dx/y(modp)\pm\sqrt{-d} \equiv x/y \pmod p
    为了方便和我一样不会数论的朋友,写一下推导。
    x2+dy20(modp)x2dy2(modp)x2y2d(modp)xy±d(modp)\begin{aligned} x^2 + d\cdot y^2&\equiv 0 &\pmod p\\ x^2&\equiv -d\cdot y^2 &\pmod p\\ \frac{x^2}{y^2}&\equiv -d &\pmod p\\ \frac{x}{y}&\equiv \pm\sqrt{-d} &\pmod p\\ \end{aligned}
    证明
    假设存在两组不同的非负整数解 (a,b)(a, b)(c,d)(c, d),满足 a2+b2=pa^2 + b^2 = pc2+d2=pc^2 + d^2 = p,且 {a,b}{c,d}\{a, b\} \neq \{c, d\}。由于 pp 是质数,显然 a,b,c,da, b, c, d 均为正整数。
    考虑模 pp 下的运算。由 a2+b2=pa^2 + b^2 = pc2+d2=pc^2 + d^2 = p,结合刚刚的讨论,a/ba/bc/dc/d 都是模 pp1-1 的平方根。由于 p1(mod4)p \equiv 1 \pmod{4}1-1 的二次剩余恰好有两个互为相反数的解,a/b±c/d(modp)a/b \equiv \pm c/d \pmod{p}
    a/bc/d(modp)a/b \equiv c/d \pmod{p},则 adbc0(modp)a d - b c \equiv 0 \pmod{p}
    由于 a,b,c,d<pa, b, c, d < \sqrt{p},显然 ad<pa d < pbc<pb c < p,所以 adbc<p|a d - b c| < p
    因此 adbc=0,a/b=c/da d - b c = 0, a/b = c/d
    a/bc/d(modp)a/b \equiv -c/d \pmod{p},容易得到 ad+bc0(modp)a d + b c \equiv 0 \pmod{p}
    由于 0<a,b,c,d<p0 < a, b, c, d < \sqrt{p},我们有 0<ad+bc<2p0 < a d + b c < 2p,所以 ad+bc=pa d + b c = p
    发挥一下注意力,我们有:
    (ad+bc)2+(acbd)2=a2d2+2abcd+b2c2+a2c22abcd+b2d2=a2(c2+d2)+b2(c2+d2)=(a2+b2)(c2+d2)=p2\begin{aligned} (a d + b c)^2 + (a c - b d)^2&= a^2 d^2 + 2 a b c d + b^2 c^2 + a^2 c^2 - 2 a b c d + b^2 d^2\\ &= a^2 (c^2 + d^2) + b^2 (c^2 + d^2)\\ &= (a^2 + b^2)(c^2 + d^2)\\ &= p^2 \end{aligned}
    由于 ad+bc=pa d + b c = p,我们有 p2+(acbd)2=p2p^2 + (a c - b d)^2 = p^2,因此 acbd=0,ac=bda c - b d = 0, a c = b d,我们得到 a/b=d/ca/b = d/c,这与早些时候得到的 a/b=c/da/b = c/d 似乎本质相同(c,dc,d 顺序无关),放在一起讨论。
    k=a/b=d/ck = a/b = d/c,则 a=kba = k bd=kcd = k c。代入 a2+b2=pa^2 + b^2 = p 得到 k2b2+b2=b2(k2+1)=pk^2 b^2 + b^2 = b^2 (k^2 + 1) = p。类似地有 c2+k2c2=c2(k2+1)=pc^2 + k^2 c^2 = c^2 (k^2 + 1) = p
    因此,b2(k2+1)=c2(k2+1)b^2 (k^2 + 1) = c^2 (k^2 + 1),从而 b=cb = c。于是 a=kb=kca = k b = k cd=kc=kbd = k c = k b,所以 a=da = d,因此 {a,b}={c,d}\{a, b\} = \{c, d\}
    综上,pp 表示为两个平方数之和的表示在无序意义下是唯一的。
那么就简单了,每个质数写成高斯整数之后,只有一种本质不同的表示方法,顶多交换一下两个维度。直接对着搜索,枚举两类表示方法分别出现了几次,复杂度就是对的。
当然了,答案的两维也可以交换,如果担心漏解了,可以加上这一步,然后再去重。
除此之外再次强调,一堆复数乘起来可能有负的,记得取绝对值。使用 128 位整数来防止乘法导致的溢出。
给出一份参考代码,去除了宏定义与缺省源,它的语义应该比较明确,可以当作伪代码读。
时间复杂度,由于我数论不太行,可能只能分析到 log2\log^2 级别,不过仍旧是够用的,主要是我不知道一些数值应该用什么符号。据我观察,另一篇题解似乎与这个解法本质相同,复杂度也应该类似吧。
CPP
struct cpx{
	i128 x,y;
	cpx(i128 p=0,i128 q=0){x=p,y=q;}
	void operator=(const i128&p){*this={p,0};}
	cpx operator*(const cpx&c)const{
		return cpx(x*c.x-y*c.y,x*c.y+y*c.x);
	}
};//复数类
template<class T>
T q_pow(T a,ll b){
	T res;
	for(res=1;b;b>>=1,a=a*a)
		if(b&1)res=res*a;
	return res;
}
i128 _abs(i128 a){
	return a>=0?a:-a;
}
void dfs(int i,cpx res,const vector<pair<cpx,int>>&vt,vector<cpx>&ret){
	if(i==(int)vt.size()){
		res.x=_abs(res.x),
		res.y=_abs(res.y),
		ret.push_back(res),
		swap(res.x,res.y),
		ret.push_back(res);
		return;
	}
	vector<cpx>p0;
	cpx it=vt[i],vl=1;
	for(int c=0;c<=vt[i].y;c++,vl=vl*it)
		p0.push_back(vl);
	swap(it.x,it.y),vl=1;
	for(int c=0;c<=vt[i].y;c++,vl=vl*it)
		//枚举:有 c 个高斯整数交换了两维,而 vt[i].y-c 个没有交换
		dfs(i+1,res*p0[vt[i].y-c]*vl,vt,ret);
}
pair<ll, ll> Cornacchia(const ll& P, ll p, ll t, ll d);//等下给出完整实现
signed main(){
	for(cin(T);T;T--){
		cin(n);
		vector<ll>d=PollardRho::factor(n);//质因数分解
		__gnu_pbds::gp_hash_table<ll,int>mp;
		for(ll&pr:d)mp[pr]++;
		if([&]()->bool{
			for(auto[v,t]:mp)
				if(v%4==3&&t%2==1)return 1;
			return 0;
		}()){
			puts("0");
			continue;
		}
		cpx res=1;
		vector<cpx>ret;
		vector<pair<cpx,int>>vt;
		for(auto[v,t]:mp){
			if(v==2)
				res=res*q_pow(cpx(1,1),t);//其实理论上直接加入 vt 也是对的,交换两个 1 不会得到错的解,但还是稍微精细一点好了
			else if(v%4==3)
				vt.push_back({cpx(v,0),t/2});
			else{
				ll I=Cipolla::getI(v);//求 v-1 也就是 -1 的二次剩余
				pair<ll,ll> w=Cornacchia(v,v,I,1);
				vt.push_back({cpx(w.x,w.y),t});
			}
		}
		dfs(0,res,vt,ret);
		auto cmp1=[&](cpx a,cpx b){
			return tie(a.x,a.y)<tie(b.x,b.y);
		};
		auto cmp2=[&](cpx a,cpx b){
			return tie(a.x,a.y)==tie(b.x,b.y);
		};
		sort(all(ret),cmp1),
		ret.erase(unique(all(ret),cmp2),ret.end());
		print(ret.size()),pc('\n');
		for(auto[x,y]:ret)
			print(x),pc(' '),print(y),pc('\n');
	}
	return 0;
}

Cornacchia 算法

进入正题。
只讨论经典情形。
设我们需要求方程 x2+dy2=px^2+d\cdot y^2 = p 的一组解 (x,y)(x,y),其中 pp 是奇素数且 pdp\nmid d,常见的特例是 d=1d=1
算法假定模方程 t2d(modp)t^2\equiv -d\pmod p 存在解,并断言这是原方程有解的必要条件。当 d>1d> 1 时这个条件并不是充分的,需要额外验证。
算法流程很简单。
  1. 取一个合适的 t(0,p)t\in(0,p) 作为所有 t2d(modp)t^2\equiv -d\pmod p 的解的代表。
    • 使用合适的二次剩余算法,比如 Cipolla 算法,可以很快地完成这一步。
    • 如果取了 t(0,p/2]t\in(0,p/2] 的较小的代表考虑,证明可能会稍微方便一点,但取哪个都不影响正确性。
  2. (p,t)(p,t) 做辗转相除法,尝试得到一个余数序列 rr,流程大概是 r0=p,r1=t,ri+1=ri1modri(i1)r_0=p,r_1=t,r_{i+1}=r_{i-1}\bmod r_i(i\ge1) 这样不断推下去,直到取到第一个足够小的余数 rmr_m,满足 rm2pr_{m}^2\le p
  3. x=rmx=r_m,检验 (px2)/d(p-x^2)/d 是否为整数,然后检验是否为完全平方数。若是,则输出解 (x,(px2)/d)(x,\sqrt {(p-x^2)/d}),否则报告无解。
下面是一个可行的简短示例。
CPP
using ll = long long;
pair<ll, ll> Cornacchia(const ll& P, ll p, ll t, ll d) {
	if ((__int128) t * t <= P) {
		if ((P - t * t) % d != 0)
			return make_pair(-1, -1);
		ll y = (ll)(sqrt((P - t * t) / d) + .5);
		//为避免潜在精度误差,最好手动实现一个整数平方根算法
		if (y * y * d == P - t * t) 
			return make_pair(t, y);
		else return make_pair(-1, -1); 
	}
	return Cornacchia(P, t, p % t, d);
}
值得注意的是,虽然刚刚没怎么讨论符号,但是容易看出这个实现解出来的 xxyy 都是非负的,我们有 0x,yp0\le x,y\le \sqrt p
即使只是对于 Cornacchia 算法,复杂度瓶颈也不在上述的辗转相除上,而是在求二次剩余上。

证明

受限于时间和水平,我只能给出大概的思路和前几步,如果你有兴趣,不妨试着完整证明一遍。
欧几里得算法有一个结论。假设我们在对 (p,t)(p,t) 做辗转相除,将余数序列 rr 拿出来,归纳可以证明,每个余数都可以写成 ri=Aip+Bitr_i=A_i\cdot p+B_i\cdot t 的形式,其中 Ai,BiZA_i,B_i\in \mathbb Z
ri=Aip+Bitr_i=A_i\cdot p+B_i\cdot t
为了方便和我一样不会数论的朋友,写一下解释。
i=0,1i=0,1 可直接给出:r0=1p+0t,r1=0p+1tr_0=1\cdot p+0\cdot t,r_1= 0\cdot p+1\cdot t
对更大的 ii,我们有 ri+1=ri1modri=ri1ri1/ririr_{i+1}=r_{i-1}\bmod r_i=r_{i-1}-\lfloor r_{i-1}/r_i\rfloor \cdot r_i
当然也就可以递推给出 Ai+1=Ai1ri1/riAi,Bi+1=Bi1ri1/riBiA_{i+1} = A_{i-1} - \lfloor r_{i-1}/r_i\rfloor A_i,B_{i+1} = B_{i-1} -\lfloor r_{i-1}/r_i\rfloor B_i
顺便可以发现,因为 ri1/ri1\lfloor r_{i-1}/r_i\rfloor\ge 1,所以有些系数的绝对值有单调性。
另外还有一个比较容易得到的结论。若 (x,y)(x,y) 是方程 x2+dy2=px^2 + d\cdot y^2 = p 的一组非负整数解,且 y≢0(modp)y \not \equiv 0 \pmod p,且 t±dx/y(modp)t \equiv \pm\sqrt{-d} \equiv x/y \pmod p(这一点参考刚早些时候的证明),则存在整数 A,BA,B 使 x=Ap+Btx = Ap+Bt,事实上 B=yB = y
证明:由 tx/y(modp)t \equiv x/y\pmod ptyx(modp)ty \equiv x \pmod p。因此存在整数 kk 使得 ty=x+kpty = x + kp,即 x=kp+ytx = -kp + yt
A=k,B=yA= −k, B= y,得到 x=Ap+Btx = Ap + Bt,其中 B=y0B=y\ge 0
所以我们发现,这个形式和“每个余数都可以写成 ri=Aip+Bitr_i=A_i\cdot p+B_i\cdot t 的形式”看起来有点像。
接下来可以推出下一个结论。在所有能表示为 Ap+BtAp + Bt 且绝对值不大于 tt 的正整数中,欧几里得算法产生的余数序列恰好包含这些数,而且是按大小递减出现的。换句话说,任何形式为 Ap+BtAp+Bt 的数,如果满足 0<Ap+Btt0<|Ap+Bt|\le t,必在 rr 序列中出现过。进而可以推出 xx 一定会在里面出现过。
证明需要用到连分数理论,很不幸,我不会,帮不了你。
如果你有兴趣,可以阅读论文 F. Morain, J.-L. Nicolas, "On Cornacchia's algorithm for solving the diophantine equation u^2 + dv^2 = m", 1990 研究具体证明方法。
AI 对论文证明的解读

1. 问题介绍

Cornacchia 算法用于求解如下形式的丢番图方程:
u2+dv2=mu^2 + d v^2 = m
其中 ddmm 为互质的正整数。该算法最早由意大利数学家 G. Cornacchia 在 1908 年提出,基于欧几里得算法和连分数理论。在现代密码学中,该算法在椭圆曲线素性证明中有重要应用。

2. 算法描述

Cornacchia 算法的基本步骤如下:
  1. 输入:互质的正整数 ddmm
  2. 步骤
    • 求解同余方程 x2d(modm)x^2 \equiv -d \pmod{m},得到解 x0x_0(若不存在解,则原方程无解)
    • (m,x0)(m, x_0) 应用欧几里得算法,生成余数序列 r0,r1,,rkr_0, r_1, \ldots, r_k
    • 找到第一个满足 rk2<mr_k^2 < m 的余数 rkr_k
    • 检查 (mrk2)/d(m - r_k^2)/d 是否为完全平方数
    • 若是,则 u=rk,v=(mrk2)/du = r_k, v = \sqrt{(m - r_k^2)/d} 为解;否则无解

3. 证明思路概述

证明的核心思想是将原问题转化为三个子问题:
  1. 问题 P\mathcal{P}:求解 u2+dv2=mu^2 + dv^2 = m
  2. 问题 T\mathcal{T}(广义 Thue 问题):求互质整数 u,vu, v 使得 u+x0v0(modm)u + x_0v \equiv 0 \pmod{m} 且满足特定界限
  3. 问题 D\mathcal{D}(丢番图逼近问题):求分数 p/qp/q 使得 qxp<1/Q|qx - p| < 1/Q
通过连分数理论建立这些问题之间的联系,最终证明算法的正确性。

4. 详细证明

4.1 问题转化(Section 2)

(u,v)(u, v) 是方程 u2+dv2=mu^2 + dv^2 = m 的解,且 u,vu, v 互质。则有:
u2dv2(modm)u^2 \equiv -dv^2 \pmod{m}
由于 vvmm 互质(因为 u,vu, v 互质且 u2+dv2=mu^2 + dv^2 = m),可得:
(u/v)2d(modm)(u/v)^2 \equiv -d \pmod{m}
x0x_0 为模 mmd-d 的平方根,即 x02d(modm)x_0^2 \equiv -d \pmod{m},则有:
u+x0v0(modm)(1)u + x_0v \equiv 0 \pmod{m} \tag{1}
此外,由 u2+dv2=mu^2 + dv^2 = m 可得界限:
0<u<m,0<v<m/d(2)0 < |u| < \sqrt{m}, \quad 0 < v < \sqrt{m/d} \tag{2}
这就将原问题转化为问题 T\mathcal{T}:求互质整数 u,vu, v 满足 (1) 和 (2)。
由 (1) 可得存在整数 kk 使得:
u+x0v=kmu + x_0v = km
代入 (2) 得:
vx0mk=um<1m1m/d=1m/d(3)\left| v \cdot \frac{x_0}{m} - k \right| = \left| \frac{u}{m} \right| < \frac{1}{\sqrt{m}} \cdot \frac{1}{\sqrt{m/d}} = \frac{1}{\sqrt{m/d}} \tag{3}
x=x0/m,Q=m/dx = x_0/m, Q = \sqrt{m/d},则 (3) 变为:
vxk<1Q|vx - k| < \frac{1}{Q}
这就转化为问题 D\mathcal{D}:求既约分数 k/vk/v 使得 vxk<1/Q|vx - k| < 1/QvQv \leq Q.

4.2 连分数理论(Section 3)

xx 为实数,其连分数展开为:
x=[a0,a1,a2,]=a0+1a1+1a2+x = [a_0, a_1, a_2, \ldots] = a_0 + \frac{1}{a_1 + \frac{1}{a_2 + \cdots}}
定义序列 pn,qnp_n, q_n 为:
  • p2=0,p1=1,pn=anpn1+pn2p_{-2} = 0, p_{-1} = 1, p_n = a_n p_{n-1} + p_{n-2}
  • q2=1,q1=0,qn=anqn1+qn2q_{-2} = 1, q_{-1} = 0, q_n = a_n q_{n-1} + q_{n-2}
pn/qnp_n/q_n 称为第 nn收敛子(convergent)。
此外,定义中间收敛子(intermediate convergent)为:
pn,rqn,r=rpn+1+pnrqn+1+qn,1ran+21\frac{p_{n,r}}{q_{n,r}} = \frac{r p_{n+1} + p_n}{r q_{n+1} + q_n}, \quad 1 \leq r \leq a_{n+2} - 1
关键性质:
  1. 行列式性质qnpn1pnqn1=(1)n1q_n p_{n-1} - p_n q_{n-1} = (-1)^{n-1}
  2. 逼近误差 qnxpn=1an+1qn+qn1<1qn+1|q_n x - p_n| = \frac{1}{a'_{n+1} q_n + q_{n-1}} < \frac{1}{q_{n+1}} 其中 an=[an,an+1,]a'_n = [a_n, a_{n+1}, \ldots]
  3. 最佳逼近定理:满足 qxp<1/(2q)|q x - p| < 1/(2q) 的既约分数 p/qp/q 必为 xx 的收敛子

4.3 解决 Problem D\mathcal{D}(Section 4)

对于问题 D\mathcal{D}:求既约分数 p/qp/q 使得 qxp<1/Q|q x - p| < 1/QqQq \leq Q.
由最佳逼近定理,这样的分数必为 xx 的收敛子或中间收敛子。具体地:
qnQ<qn+1q_n \leq Q < q_{n+1},则可能的解为:
  • 主收敛子:pn/qnp_n/q_n
  • 中间收敛子:pn1,1/qn1,1p_{n-1,1}/q_{n-1,1}pn1,an+11/qn1,an+11p_{n-1,a_{n+1}-1}/q_{n-1,a_{n+1}-1}
算法 THUE(x, Q) 如下:
  1. 计算 xx 的连分数展开,直到 qnQ<qn+1q_n \leq Q < q_{n+1}
  2. r=(Qqn1)/qnr = \lfloor (Q - q_{n-1})/q_n \rfloor
  3. r=0r = 0,测试 pn1/qn1p_{n-1}/q_{n-1} 是否满足条件
  4. r1r \geq 1,测试 pn1,r/qn1,rp_{n-1,r}/q_{n-1,r} 是否满足条件
  5. 返回所有满足条件的分数

4.4 解决 Problem P\mathcal{P}(Section 5)

现在回到原问题。设 x=x0/mx = x_0/mQ=m/dQ = \sqrt{m/d}。由问题 D\mathcal{D} 的解 k/vk/v 可得:
u=kmx0vu = km - x_0v
需验证 u2+dv2=mu^2 + dv^2 = m
定理 5.1:若问题 P\mathcal{P} 有解,则解为 u=pnmx0qn,v=qnu = p_n m - x_0 q_n, v = q_n,其中 qnm/d<qn+1q_n \leq \sqrt{m/d} < q_{n+1}.
证明
(u,v)(u, v) 为解,则存在 kk 使得 u=kmx0vu = km - x_0v,且 k/vk/v 是问题 D\mathcal{D} 的解。由连分数理论,k/vk/vx0/mx_0/m 的收敛子或中间收敛子。
通过计算范数:
N(u,v)=u2+dv2=(kmx0v)2+dv2N(u,v) = u^2 + dv^2 = (km - x_0v)^2 + dv^2
利用 x02d(modm)x_0^2 \equiv -d \pmod{m},可得:
N(u,v)(k2+d)m2(modm)N(u,v) \equiv (k^2 + d)m^2 \pmod{m}
通过细致分析收敛子和中间收敛子的性质,可以证明只有主收敛子 pn/qnp_n/q_n 能给出解。
定理 5.2:设 kk 为第一个满足 rk2<mr_k^2 < m 的索引,则解为 u=rk,v=qku = r_k, v = q_k.
证明
由欧几里得算法性质,ri=mqix0/mpir_i = m |q_i x_0/m - p_i|。当 rk2<mr_k^2 < m 时,有:
N(rk,qk)=rk2+dqk2<m+dmd=2mN(r_k, q_k) = r_k^2 + d q_k^2 < m + d \cdot \frac{m}{d} = 2m
另一方面,由 u+x0v0(modm)u + x_0v \equiv 0 \pmod{m} 可得 N(u,v)0(modm)N(u,v) \equiv 0 \pmod{m},故 N(rk,qk)=mN(r_k, q_k) = m2m2m
通过分析连分数逼近误差,可排除 N(rk,qk)=2mN(r_k, q_k) = 2m 的情况,故 N(rk,qk)=mN(r_k, q_k) = m.

5. 总结

Cornacchia 算法通过欧几里得算法和连分数理论,高效地求解了丢番图方程 u2+dv2=mu^2 + dv^2 = m。其正确性证明依赖于将原问题转化为丢番图逼近问题,并利用连分数收敛子的最佳逼近性质。
该算法在计算数论和密码学中有重要应用,特别是椭圆曲线密码学中的素性证明。

参考文献

  1. G. Cornacchia, "Su di un metodo per la risoluzione in numeri interi dell' equazione ∑_{h=0}^n C_h x^{n-h} y^h = P", Giornale di Matematiche di Battaglini, 1908
  2. F. Morain, J.-L. Nicolas, "On Cornacchia's algorithm for solving the diophantine equation u^2 + dv^2 = m", 1990
  3. H. Cohen, "A Course in Computational Algebraic Number Theory", Springer, 1993

评论

5 条评论,欢迎与作者交流。

正在加载评论...