数学 —— 数论 —— 佩尔方程与连分数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011815404/article/details/88717125

【概述】

连分数是一种特殊的繁分数,其形式为:a_1+\frac{1}{ a_2+\frac{1}{ a_3+\frac{1}{... } } }  ,通常记为:[a_1,a_2,...,a_n]=\frac{p_n}{q_n},其中 p_nq_n 称为连分数多项式,对于任意的 a 均为一次式,它们的比值称为第 n 个渐进值渐进分数。

佩尔(Pell)方程是一种不定二次方程,其与连分数,二次型,代数论等有着重要的联系。

其形式为:x^2-dy^2=1,(d\in N^+),其中 d 不为非平方数

【佩尔方程迭代公式】

定义:设 p、q 为整数,且满足 p^2-Dq^2=T,则称 a=p-q\sqrt D 给出该方程的解

推论:

设 \left\{\begin{matrix}a=x_1-y_1\sqrt D \\ b=x_2-y_2\sqrt D \end{matrix}\right. 给出方程 x^2-Dy^2=T 的解

则:ab=A-B\sqrt D 给出方程 x^2-Dy^2=T^2 的解,其中 \left\{\begin{matrix}A=x_1x_2+Dy_1y_1 \\ B=x_1y_2+x_2y_1\:\:\:\: \end{matrix}\right.

取 d=D,T=1,则有佩尔方程 x^2-dy^2=1,(d\in N^+) 

若佩尔方程的最小特解为 (x_1,y_1),故有迭代公式:\left\{\begin{matrix}x_n=x_{n-1}x_1+dy_{n-1}y_1 \\ y_n=x_{n-1}y_1+y_{n-1}x_1\:\:\:\: \end{matrix}\right.

将迭代公式写为矩阵的形式,有:\begin{pmatrix}x_k \\ y_k \end{pmatrix}=\begin{pmatrix}x_1\:\:\:dy_1 \\ y_1\:\:\:x_1 \end{pmatrix}^{k-1}\begin{pmatrix}x_1 \\ y_1 \end{pmatrix},可以通过矩阵快速幂找出第 k 大的解

【连分数求解佩尔方程】

对于连分数 [a_1,a_2,...,a_n]=\frac{p_n}{q_n} 的渐进值来讲,有着递归关系式:\left\{\begin{matrix}p_1=a_1,p_2=a_2a_1+1,...,p_{n+1}=a_{n+1}p_n+p_{n-1} \\ q_1=1,\:\:\:\:q_2=a_2,\:\:\:.....\:,\:\:\:q_{n+1}=a_{n+1}q_n+q_{n-1} \end{matrix}\right.,n\geqslant 2

通过数学归纳法,可得到关系式:p_{n+1}q_n-p_nq_{n+1}=(-1)^{n-1},n\geqslant 1

定义:对于正整数 p、q,若有 |p^2-a^2q^2|<a,则比值 \frac{p}{q} 必为 a 的一个渐近值

由此可得:佩尔方程的全部根的集合为 x^2-dy^2=(p^2-dq^2)^n=1

由佩尔方程的迭代公式\left\{\begin{matrix}x_n=x_{n-1}x_1+dy_{n-1}y_1 \\ y_n=x_{n-1}y_1+y_{n-1}x_1\:\:\:\: \end{matrix}\right.可得出佩尔方程的最小解

即:\left\{\begin{matrix}x=\frac{(p+\sqrt d\:q)^n+(p-\sqrt d\:q)^n}{2} \\ y=\frac{(p+\sqrt d\:q)^n-(p-\sqrt d\:q)^n}{2\sqrt d} \end{matrix}\right.

【模版】

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

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/88717125
今日推荐