版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011815404/article/details/88717125
【概述】
连分数是一种特殊的繁分数,其形式为: ,通常记为:,其中 和 称为连分数多项式,对于任意的 a 均为一次式,它们的比值称为第 n 个渐进值渐进分数。
佩尔(Pell)方程是一种不定二次方程,其与连分数,二次型,代数论等有着重要的联系。
其形式为:,其中 d 不为非平方数
【佩尔方程迭代公式】
定义:设 p、q 为整数,且满足 ,则称 给出该方程的解
推论:
设 给出方程 的解
则: 给出方程 的解,其中
取 ,则有佩尔方程
若佩尔方程的最小特解为 ,故有迭代公式:
将迭代公式写为矩阵的形式,有:,可以通过矩阵快速幂找出第 k 大的解
【连分数求解佩尔方程】
对于连分数 的渐进值来讲,有着递归关系式:
通过数学归纳法,可得到关系式:
定义:对于正整数 p、q,若有 ,则比值 必为 a 的一个渐近值
由此可得:佩尔方程的全部根的集合为
由佩尔方程的迭代公式可得出佩尔方程的最小解
即:
【模版】
1.暴力寻找最小解
int x[N],y[N];
void pell(int &a,int &b,int d){//暴力寻找pell方程最小解
b=1;
while(true){
a=(LL)sqrt(d*b*b+1);
if(a*a-d*b*b==1)
break;
b++;
}
}
int main(){
int d;
while(scanf("%d",&d)!=EOF){
int m=(int)sqrt((double)d);
if(m*m==d){//d不能为完全平方数
cout<<"No Solution"<<endl;
continue;
}
int a=0,b=0;
pell(a,b,d);//暴力找到最小解
cout<<a<<" "<<b<<endl;
}
return 0;
}
2.迭代公式求前 n 个解
使用迭代公式求解 pell 方程的前 n 个解时,应先用暴力寻找到最小解,然后再套用迭代公式求出前 n 个解,由于 pell 方程相邻两解之间的差值较大,n 一般很小
int x[N],y[N];
void pell(int &a,int &b,int d){//暴力寻找pell方程最小解
b=1;
while(true){
a=(LL)sqrt(d*b*b+1);
if(a*a-d*b*b==1)
break;
b++;
}
}
int main(){
int d;
while(scanf("%d",&d)!=EOF){
int m=(int)sqrt((double)d);
if(m*m==d){//d不能为完全平方数
cout<<"No Solution"<<endl;
continue;
}
int a=0,b=0;
pell(a,b,d);//暴力找到最小解
x[1]=a,y[1]=b;//第一组解
for(int i=2;i<=10;i++){//递推公式
x[i]=x[i-1]*x[1]+2*y[i-1]*y[1];
y[i]=x[i-1]*y[1]+y[i-1]*x[1];
}
for(int i=1;i<=10;i++)
cout<<x[i]<<" "<<y[i]<<endl;
}
return 0;
}
3.连分数法
当要求 pell 方程的最小解时,暴力可能会 TLE,此时可以使用连分数法,其关键是计算连分数的展开
int a[20000];
bool pell(int &x,int &y,int d){
int m=(int)sqrt((double)d);
if(m*m==d)//d不能为完全平方数
return false;
//将d以连分数形式存储
int num=0;//连分数数位
double sq=sqrt(d);//d的高精度根,相当于r0
a[num++]=m;//存储整数部分
int b=m;//当前整数部分
int c=1;//连分数最终展开时的分母
double temp;//连分数展开时的每一项
do{
c=(d-b*b)/c;
temp=(sq+b)/c;
a[num++]=(int)(floor(temp));
b=a[num-1]*c-b;
}while(a[num-1]!=2*a[0]);//当有一位等于整数两倍时结束
//将连分数形式化为分子分母形式,即求p、q两个值
int p=1,q=0;
for(int i=num-2;i>=0;i--){
int temp=p;
p=q+p*a[i];
q=temp;
}
if((num-1)%2){//连分数长度为奇数时
x=2*p*p+1;
y=2*p*q;
}
else{//连分数长度为偶数时
x=p;
y=q;
}
return true;
}
int main(){
int d;
while(scanf("%d",&d)!=EOF){
int x,y;
if(pell(x,y,d))
cout<<x<<" "<<y<<endl;
else
cout<<"No Solution"<<endl;
}
return 0;
}