Pell方程

pell方程

1.形式:x^2 - dy^2 =1

2.递推形式:

[a_{0}; a_{1}, a_{2}, a_{3}, \,\ldots ]的渐近分数列,由连分数理论知存在i使得(pi,qi)为佩尔方程的解。取其中最小的i,将对应的 (pi,qi)称为佩尔方程的基本解,或最小解,记作(x1,y1),则所有的解(xi,yi)可表示成如下形式:

x_{i}+y_{i}{\sqrt  n}=(x_{1}+y_{1}{\sqrt  n})^{i}

或者由以下的递回关系式得到:

\displaystyle x_{i+1} = x_1 x_i + n y_1 y_i,

\displaystyle y_{​{i+1}}=x_{1}y_{i}+y_{1}x_{i}

3.求解最小解

1)暴力枚举y的值,对等式做判定

2)通过d^{1/2}的连分数表示确定最小解

连分数构造方法:

 

4.应用

1)求最小特解

POJ :3292


import java.math.BigInteger;
import java.util.Scanner;

public class Main
{
    public static void solve(int n)
    {
        BigInteger N, p1, p2, q1, q2, a0, a1, a2, g1, g2, h1, h2,p,q;
        g1 = q2 = p1 = BigInteger.ZERO;
        h1 = q1 = p2 = BigInteger.ONE;
        a0 = a1 = BigInteger.valueOf((int)Math.sqrt(1.0*n));
        BigInteger ans=a0.multiply(a0);
        if(ans.equals(BigInteger.valueOf(n)))
        {
            System.out.println("No solution!");
            return;
        }
        N = BigInteger.valueOf(n);
        while (true)
        {
            g2 = a1.multiply(h1).subtract(g1);
            h2 = N.subtract(g2.pow(2)).divide(h1);
            a2 = g2.add(a0).divide(h2);
            p = a1.multiply(p2).add(p1);
            q = a1.multiply(q2).add(q1);
            if (p.pow(2).subtract(N.multiply(q.pow(2))).compareTo(BigInteger.ONE) == 0) break;
            g1 = g2;h1 = h2;a1 = a2;
            p1 = p2;p2 = p;
            q1 = q2;q2 = q;
        }
        System.out.println(p+" "+q);
    }

    public static void main(String[] args)
    {
        Scanner cin = new Scanner(System.in);
        while(cin.hasNextInt())
        {
            solve(cin.nextInt());
        }
    }
} 

2)求第K解 HDU 3292

求出特解后,进行矩阵快速幂(注意当d为完全平方数时只有平凡解(\pm 1,0) )。

第K解:

$$ \left[ \begin{matrix} xi\\ yi \\ \end{matrix} \right] \tag{3} $$ = $$ \left[ \begin{matrix} x1&dy1 \\ y1 & x1 \end{matrix} \right] \tag{3} $$ ^{k-1} * $$ \left[ \begin{matrix} x1 \\ y1 \end{matrix} \right] \tag{3} $$

code:

#include <bits/stdc++.h>
using namespace std;
//#define N 100010
#define LL long long
#define PB push_back
#define pii pair<int, int>
#define MP make_pair

typedef unsigned long long ull;
typedef long long ll;

const int maxn = 3e5 + 10;
const int mod = 8191;

struct mat
{
    int s[2][2];
};

mat mul(mat a, mat b)
{
    mat c;
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++){
            c.s[i][j] = 0;
            for (int k = 0; k < 2; k++)
            {
                c.s[i][j] += a.s[i][k] * b.s[k][j];
                c.s[i][j] %= mod;
            }
        }
    return c;
}

mat qpow(mat a, int b)
{
    mat c;
    c.s[0][0] = c.s[1][1] = 1;
    c.s[1][0] = c.s[0][1] = 0;
    while (b)
    {
        if (b & 1)
            c = mul(c, a);
        a = mul(a, a);
        b >>= 1;
    }
    return c;
}

pii solve(ll n)
{
    ll N, p1, p2, q1, q2, a0, a1, a2, g1, g2, h1, h2, p, q;
    g1 = q2 = p1 = 0;
    h1 = q1 = p2 = 1;
    a0 = a1 = sqrt(n * 1.0);
    ll ans = a0 * a0;
    N = n;
    // cout<<ans<<' '<<n<<endl;
    if (ans == N)
        return MP(1, 0);
    while (true)
    {
        g2 = a1 * h1 - g1;
        h2 = (N - g2 * g2) / h1;
        a2 = (g2 + a0) / h2;
        p = a1*p2 + p1;
        q = a1*q2 + q1;        
        // cout<<p<<' '<<q<<endl;
        if (p * p == (N * q * q + 1))
            break;
        g1 = g2;
        h1 = h2;
        a1 = a2;
        p1 = p2;
        p2 = p;
        q1 = q2;
        q2 = q;
    }
    return MP(p, q);
}

int main()
{
    int n, k;
    while(scanf("%d%d",&n,&k)==2){
        // cout<<n<<' '<<k<<endl;
        pii ans = solve(n);
        if (ans.second == 0){
            puts("No answers can meet such conditions");
            continue;
        }
        mat a;
        int p = ans.first;
        int q = ans.second;
        // cout<<p<<' '<<q<<endl;
        a.s[0][0] = p;
        a.s[0][1] = n * q;
        a.s[1][0] = q;
        a.s[1][1] = p;
        a = qpow(a, k - 1);
        int x = (a.s[0][0] * p + a.s[0][1] * q) % mod;
        printf("%d\n", x);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值