题解:P14551 【模板】Pell 方程
xcb__fhuHGFgf56454
·
·
题解
题目传送门
update: 2026.1.31 修改三角函数的笔误。
:::info[前言]
Pell 方程,看着很难,实际搞懂了原理还是很简单的。
本篇题解讲述关于 Pell 方程的详细解法。
:::
引入
$$
\sqrt{2}=\vert 1+i \vert
$$
$$
\sqrt{2}=\sec45\degree
$$
$$
\sqrt{2}=\sum_{k=0}^{\infty} \binom{\frac{1}{2}}{k}
$$
但要说里面最有趣的那一个,应该就是这个连分数。
$$
\sqrt{2}=1+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{\dots}}}}}
$$
然而,我们并不能通过这个连分数直接计算得到 $\sqrt{2}$,因为有的时候我们会得到 $\pm\sqrt{2}$ 两个答案。
$$
\begin{align*}
\sqrt{2} &=1+(\sqrt{2}-1)\\
&=1+\frac{(\sqrt{2}-1)(\sqrt{2}+1)}{(\sqrt{2}+1)}\\
&=1+\frac{1}{1+\sqrt{2}}\\
&=1+\frac{1}{2+\frac{1}{1+\sqrt{2}}}\\
&=1+\frac{1}{2+\frac{1}{2+\frac{1}{1+\sqrt{2}}}}\\
&=1+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{\dots}}}}}
\end{align*}
$$
$$
\begin{align*}
-\sqrt{2} &=1+(-\sqrt{2}-1)\\
&=1+\frac{(-\sqrt{2}-1)(-\sqrt{2}+1)}{(-\sqrt{2}+1)}\\
&=1+\frac{1}{1-\sqrt{2}}\\
&=1+\frac{1}{2+\frac{1}{1-\sqrt{2}}}\\
&=1+\frac{1}{2+\frac{1}{2+\frac{1}{1-\sqrt{2}}}}\\
&=1+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{2+\frac{1}{\dots}}}}}
\end{align*}
$$
或者:
$$
\begin{align*}
x&=1+\frac{1}{1+x}\\
\Rightarrow x&=\pm\sqrt{2}
\end{align*}
$$
想要得到 $\sqrt{2}$,我们需要通过一些其他手段,例如,我们可以把这个连分数给截断,假设它是一个有限连分数。
$$
\begin{align*}
1&=1\\
1+\frac{1}{2}&=\frac{3}{2}\\
1+\frac{1}{2+\frac{1}{2}}&=\frac{7}{5}\\
1+\frac{1}{2+\frac{1}{2+\frac{1}{2}}}&=\frac{17}{12}
\end{align*}
$$
只要截断的这些值能收敛到 $\sqrt{2}$,那 $\sqrt{2}$ 就是这个连分数的值了。
$$
\begin{align*}
1-\sqrt{2}&\approx-0.41421356\\
\frac{3}{2}-\sqrt{2}&\approx0.08578643\\
\frac{7}{5}-\sqrt{2}&\approx-0.01421356\\
\frac{17}{12}-\sqrt{2}&\approx0.00245310
\end{align*}
$$
可以发现,截断的值越来越接近 $\sqrt{2}$。为了更简洁,我们可以将上面的值的平方与 $2$ 进行比较。
$$
\begin{align*}
1^2&=2-\frac{1}{1}\\
(\frac{3}{2})^2&=2+\frac{1}{4}\\
(\frac{7}{5})^2&=2-\frac{1}{25}\\
(\frac{17}{12})^2&=2+\frac{1}{144}
\end{align*}
$$
最后得到的结果是:分子的平方和分母的平方的两倍相差 $1$。这的原理是什么呢?
## $\sqrt{2}$ 的逼近
按照我们的计算结果,可以将截断值分为两类。
- 一类是减出来为 $1$ 的。
$$
\begin{align*}
3^2-2\times2^2&=1\\
17^2-2\times12^2&=1
\end{align*}
$$
- 一类是减出来为 $-1$ 的。
$$
\begin{align*}
1^2-2\times1^2&=-1\\
7^2-2\times5^2&=-1
\end{align*}
$$
我们将这些截断值的分子当做横坐标,分母当做纵坐标,我们可以将截断值在坐标轴上表示出来。

其中蓝点是减出来为 $-1$ 的那一类,绿点是减出来为 $1$ 的那一类。我们可以知道所有蓝点都在双曲线 $x^2-2 y^2=-1$ 上,所有绿点都在双曲线 $x^2-2 y^2=1$ 上。换句话说,这上面的点都是这两条双曲线上的整点。
特别的,这两条双曲线都有一个相同的渐近线:$y=\sqrt{2}x$。
我们连接原点和双曲线上的点,这条直线的斜率就是双曲线上的点表示的数的倒数,越远的点斜率越接近 $\frac{\sqrt{2}}{2}$。
为什么所有截断值都一定在这两条双曲线上?我们要看看通分的时候是怎么计算的了。
例如,截取值的第 $3,4$ 项,分别是 $\frac{7}{5}$ 和 $\frac{17}{12}$ ,它们的计算过程分别是这样:
$$
\begin{equation*}
\begin{split}
1+\frac{1}{2+\frac{1}{2}}&=1+\frac{2}{5}\\
&=\frac{7}{5}
\end{split}
\end{equation*}
$$
$$
\begin{equation*}
\begin{split}
1+\frac{1}{2+\frac{1}{2+\frac{1}{2}}}&=1+\frac{1}{2+\frac{2}{5}}\\
&=1+\frac{5}{12}\\
&=\frac{17}{12}
\end{split}
\end{equation*}
$$
很明显,它们的第一步是一模一样的,都是 $\frac{2}{5}$,而到了第二步,一个 $+1$,一个 $+2$,才产生了差异。但我们仍然可以用 $\frac{7}{5}$ 的结果,因为我们可以将 $2$ 拆成 $1+1$ ,就像这样:
$$
\begin{equation*}
\begin{split}
1+\frac{1}{2+\frac{1}{2+\frac{1}{2}}}&=1+\frac{1}{1+1+\frac{2}{5}}\\
&=1+\frac{1}{1+\frac{7}{5}}\\
&=1+\frac{12}{7}\\
&=\frac{17}{12}
\end{split}
\end{equation*}
$$
也就是说,相邻的两个截断值,有这么一个递推公式:
$$
\frac{x_{i+1}}{y_{i+1}}=1+\frac{1}{1+\frac{x_{i}}{y_{i}}}=\frac{x_i+2y_i}{x_i+y_i}
$$
并且,若前一项是最简分数,后一项也不需要约分,因为:
$$
\gcd(x_{i+1},y_{i+1})=\gcd(x_i+2y_i,x_i+y_i)=\gcd(x_i,y_i)=1
$$
现在我们回到平面上,这个递推式让我们确定了平面上点的一个变换。
$$
\binom{x}{y}\to\binom{x+2y}{x+y}
$$
它不只是可以用在这些点上,它作用于整个平面。在变换后,两条双曲线会交换位置,所有点会向后移动一个位置。这种规律其实在其他双曲线上也成立。
例如,我们将 $2$ 变为 $5$,我们在双曲线 $x^2-5y^2=\pm1$ 上仍然可以找到一个变换:
$$
\binom{x}{y}\to\binom{2x+5y}{x+2y}
$$
甚至在一些更奇怪的双曲线上,这个规律也成立。比如双曲线 $x^2-3y^2=\pm1$,虽然 $x^2-3y^2=-1$ 上一个整点也没有,但我们可以在 $x^2-3y^2=1$ 上也找到一个变换:
$$
\binom{x}{y}\to\binom{2x+3y}{x+2y}
$$
这个递推关系是普适的,它能让我们从一个整点推导出下一个整点,也是 Pell 方程解的递推核心。
## Pell 方程
我们将我们上述的双曲线一般化,就得到了Pell方程的一般形式。
标准 Pell 方程:
$$
x^2-ny^2=1
$$
负 Pell 方程:
$$
x^2-ny^2=-1
$$
其中 $n$ 为正整数。
## 解的存在条件
### 标准 Pell 方程的解的存在性
若 $n$ 是完全平方数,设 $n=s^2 (s\in\mathbb{N})$,则方程可变形为
$$
(x-sy)(x+sy)=1
$$
因为 $x,y$ 都是正整数,所以
$$
x-sy=x+sy=1
$$
因此方程只有平凡解 $(\pm1,0)$,不存在正整数解。
若 $n$ 不是完全平方数,则方程一定有无穷多组正整数解。
### 负 Pell 方程的解的存在性
1. 必要条件 $1$:
若 $n$ 是完全平方数,设 $n=s^2 (s\in\mathbb{N})$,则方程可变形为
$$
(x-sy)(x+sy)=-1
$$
不存在正整数解。
2. 必要条件 $2$:
另外,对于 $n$ 的每个素因子 $p$,如果 $p\equiv3\pmod{4}$,必须满足 $p$ 在 $n$ 的分解中出现偶数次,负 Pell 方程才可能有解。
因为负 Pell 方程本质上求:
$$
x^2\equiv-1\pmod{n}
$$
由 Legendre 符号可知:
$$
\binom{-1}{p}=(-1)^{\frac{p-1}{2}}
$$
若 $p\equiv1$ 或 $2\pmod{4} \to$ 有解。
若 $p\equiv3\pmod{4}$ 且指数不为偶数 $\to$ 无解。
3. 充要条件:
$\sqrt{n}$ 的连分数周期为奇数。
这是因为标准 Pell 方程的基本解来自连分数周期的末尾,而负 Pell 方程的基本解来自连分数周期的“半周期”位置。
只有当周期长度为奇数时,“半周期”才会落在整数步上,负 Pell 方程才会有解。
## 基本解的求法
我们定义对于有解的 Pell 方程,满足所有正整数解中 $x$ 最小的那一组解 $(x_0,y_0)$,称为该方程的最小正整数解(也叫基本解)。
无论是标准 Pell 方程还是负 Pell 方程,求基本解的唯一核心方法,就是对无理数 $\sqrt{n}$ 做无限循环连分数展开,这也是求 Pell 方程基本解的通用、唯一的有效方法。
已知 $n$ 为非完全平方数,$\sqrt{n}$ 的无限循环连分数展开式的标准形式为:
$$
\sqrt{n}=[a_0;\overline{a_1,a_2,\dots,a_{l-1}}]
$$
其中:
- $a_0=\lfloor\sqrt{n}\rfloor$。
- $\overline{a_1,a_2,\dots,a_{l-1}}$ 是连分数的循环节,循环节长度为 $l$。
- 连分数是对称循环的,即 $a_1=a_{l-1},a_2=a_{l-2}\dots$。
我们通过四个核心变量的递推,完成连分数展开,同时得到展开后的渐近分数 $\frac{p_k}{q_k}$。
### 初始化
$m_0=0,d_0=1,a_0=\lfloor\sqrt{n}\rfloor
渐近分数初始项:p_{-1}=1,p_0=a_0,q_{-1}=0,q_0=1
递推公式:
\begin{cases}
m_{k+1}=d_k\cdot a_k-m_k\\
d_{k+1}=\frac{n-m_{k+1}^2}{d_k}\\
a_{k+1}=\lfloor\frac{a_0+m_{k+1}}{d_{k+1}}\rfloor
\end{cases}
同时,渐近分数同时递推:
\begin{cases}
p_{k+1}=a_{k+1}\cdot p_k+p_{k-1}\\
q_{k+1}=a_{k+1}\cdot q_k+q_{k-1}
\end{cases}
当递推到 d_{k+1}=1 时,停止递推,此时我们得到了 \sqrt{n} 的连分数展开的完整循环节,循环节长度为 l。
求解
对于非完全平方数 n 的标准Pell方程,其基本解的取值由循环节长度 l 决定:
- 若循环节长度 l 为偶数,则标准Pell方程的基本解为:(x_1,y_1)=(p_{l-1},q_{l-1})
- 若循环节长度 l 为奇数,则标准Pell方程的基本解为:(x_1,y_1)=(p_{2l-1},q_{2l-1})
对于有解的负 Pell 方程,循环节长度 l 为奇数,其基本解为 (x_0,y_0)=(p_{l-1},q_{l-1})
现在我们就能得到方程的基本解了。
基本解与全部解的关系
所有有解的 Pell 方程,已知基本解,就能推出全部正整数解,这也是 Pell 方程的核心价值所在,所有解的递推都基于基本解。
标准 Pell 方程的全部解
设标准 Pell 方程的基本解为 (x_1,y_1),则其所有正整数解满足递推公式:
\begin{cases}
x_{k+1}=x_1\cdot x_k+n\cdot y_1\cdot y_k\\
y_{k+1}=x_1\cdot y_k+y_1\cdot x_k
\end{cases}
等价于:
x_k+y_k \sqrt{n}=(x_1+y_1\sqrt{n})^k
设负 Pell 方程的基本解为 (x_0,y_0),则其所有正整数解满足:
x_k+y_k \sqrt{n}=(x_0+y_0\sqrt{n})^{2k-1}
同时,我们可以发现,负 Pell 方程的基本解平方后,就是对应标准 Pell 方程的基本解:
x_1+y_1\sqrt{n}=(x_0+y_0\sqrt{n})^2
代码
:::success[C++]
#include<bits/stdc++.h>
#define int long long
#define i128 __int128
#define y1 Y1
using namespace std;
void write(i128 x){ //输出一个__int128的数
if(x<0) cout<<'-',x=-x;
if(x>9) write(x/10);
cout<<(int)(x%10);
}
bool is2(int n){ //判断是否为平方数
int s=sqrtl(n);
return s*s==n;
}
void pell(int n){ //求解 Pell 方程
i128 x1=-1,y1=-1,x2=-1,y2=-1;
if(is2(n)){ //平方数,无解
cout<<"-1 -1\n-1 -1\n";
return;
}
//--------初始化--------
int a0=sqrtl(n),m=0,d=1,a=a0;
i128 ppre=1,p=a0,qpre=0,q=1,pp,qq;
int l=0; //循环节
//--------递推--------
while(1){
m=d*a-m;
d=(n-m*m)/d;
a=(a0+m)/d;
l++;
pp=(i128)a*p+ppre;
qq=(i128)a*q+qpre;
ppre=p,p=pp,qpre=q,q=qq;
if(d==1) break; //循环节结束
}
if(l%2==0){ //循环节长度为偶数
x1=ppre;
y1=qpre;
}
else{ //循环节长度为奇数
x2=ppre;
y2=qpre;
//标准基本解是负基本解平方
x1=x2*x2+(i128)n*y2*y2;
y1=2*x2*y2;
}
write(x1);
cout<<' ';
write(y1);
cout<<'\n';
write(x2);
cout<<' ';
write(y2);
cout<<'\n';
}
int t,n;
signed main(){
cin>>t;
while(t--){
cin>>n;
pell(n);
}
return 0;
}
提交记录
:::
后记
总体来说,只要搞懂了其中的原理,这道题还是蛮简单的。
如果这篇题解有什么不对的地方,欢迎指出,谢谢观看。