佩尔方程以及hdu6222

背景介绍

佩尔方程,是一种不定二次方程。Pell方程,古希腊和印度的数学家对此类方程的研究做了最早的贡献,由费马首先进行了深入研究,拉格朗日给出了解决方案,但后此类方程来却被欧拉误记为佩尔提出,并写入他的著作中。后人多称佩尔方程。沿续至今。

内容简介

佩尔方程是一种不定二次方程。就是如下形式的方程
x2 - dy2 = 1;
1),如果d为平方数,则方程变为了(x-√dy)(x+√dy) = 1,此时只有x = 1或-1,y=0,这两组特定解。
2),当d不为平方数时,方程有无穷多组整数解。

求解最小整数解

已知x2-dy2 = 1,
假设(x1, y1), (x2, y2),满足上面的式子,带入后得到

x 1 2 x^2_ {1} x12 - d * y 1 2 y^2_ {1} y12 = 1
x 2 2 x^2_ {2} x22 - d * y 2 2 y^2_ {2} y22 = 1

将上面两个式子相乘后得到
x 1 2 x^2_ {1} x12 * x 2 2 x^2_ {2} x22 - d x 1 2 x^2_ {1} x12 y 2 2 y^2_ {2} y22 -d y 1 2 y^2_ {1} y12 x 2 2 x^2_ {2} x22 +d2 y 1 2 y^2_ {1} y12 y 2 2 y^2_ {2} y22 = 1

整理后得到
[(x1x2)2 + (dy1y2)2] - d[(x1y2)2 + (x2y1)2] = 1

对左边和右边同时加上 2dx1y1x1y2后变为了如下形式
(x1x2 + dy1y2)2 - d(x1y2 + x2y1)2 = 1

神奇的发现它还是一个佩尔方程这个时候
x = x1x2 + dy1y2
y = x1y2 + x2y1

所以也就得到了一个递推式
xn = xn-1x1 + dy1yn-1
yn = x1yn-1 + xn-1y1

进一步变换后就能变为了下面这个矩阵,所以再求某个特解的时候可以用矩阵快速幂
在这里插入图片描述

所以我们只要求得最小解后,就能求得所有的解。
求最小解有两种方法,连分数和暴力,我现在还没太看懂连分数,后期看懂再补。

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
	int d;
	int y = 1, x = 0;
	
	cin >> d;

	while (1)
	{
		x = sqrt(1+d*pow(y, 2));
		
		if (x*x - d*y*y == 1)
		{
			break;
		}
		y++;
	}
	
	cout << x << " " << y << endl;
	
	return 0;
} 

hdu6222

接下来就到了例题了
题目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=6222

题目大意:
一个三角形三边满足t-1, t, t+1,就称为什么什么的,现在他给你一个最小的n,让你找到大于等于这个n的t。

解题思路:

求三角形面积用海伦公式来求:
在这里插入图片描述

我们设a = t-1, b = t, c = t+1

所以
在这里插入图片描述

带入海伦公式后得到
在这里插入图片描述

令x = t/2,得到
在这里插入图片描述

对两边同时平方后得到
在这里插入图片描述

因为s为整数,所以我们能知道x2-1=3*y2,整理后正好是我们今天的佩尔方程。
在看题目给的数据
在这里插入图片描述
当题目n等于1时,我们很轻松就得到了最小的t就是4,我们又知道x = t/2,所以最小的t对应最小的解,即x = 2,接着得出y=1 这便是上面佩尔方程的最小解。通过打表就能看到,当n在大于100的时候,就已经比1030次方大了,所以可以把这些解存下来,也可以每次使用矩阵快速幂。
因为数据比较大,所以使用_ _int128来做题。

#include <iostream>

using namespace std;

typedef __int128 _int;

_int num[105][2];

void read(_int &x)
{
	char ch;
	int flag = 1;
	
	x = 0;
	
	while (ch = getchar())
	{
		if (ch == '-')
		{
			flag = -1;
		}
		else if (ch>='0' && ch<='9')
		{
			break;
		}
	}
	
	x = ch - '0';
	
	while ((ch = getchar())>='0' && ch <= '9')
	{
		x = x*10 + ch-'0';
	}
	
	x*=flag;
}

void out(_int x)
{
	if (x<0)
	{
		x = -x;
		putchar('-');
	}
	
	if (x>=10)
	{
		out(x/10);
	}
	
	putchar(x%10+'0');
}

int main()
{
	num[1][0] = 2, num[1][1] = 1;
	
	for (int i=2; i<=100; i++)
	{
		num[i][0] = num[i-1][0]*num[1][0] + 3*num[i-1][1]*num[1][1];
		num[i][1] = num[i-1][1]*num[1][0] + num[1][1]*num[i-1][0];
	} 
	
	int n;
	
	cin >> n;
	
	while (n--)
	{
		_int temp = 0;
		
		read(temp);
		
		for (int i=1; i<=100; i++)
		{
			if (num[i][0] * 2 >= temp)
			{
				out(num[i][0]*2);
				puts("");
				break;
			}
		}
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值