Project Euler Problem 66

Problem 66

Consider quadratic Diophantine equations of the form:

x2 – Dy2 = 1

For example, when D=13, the minimal solution in x is 6492 – 13×1802 = 1.

It can be assumed that there are no solutions in positive integers when D is square.

By finding minimal solutions in x for D = {2, 3, 5, 6, 7}, we obtain the following:

32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1

Hence, by considering minimal solutions in x for D ≤ 7, the largest x is obtained when D=5.

Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained.

    这道题事实上是让我们寻找佩尔方程的特解。最naive的思路自然是x从1开始枚举,固定x,再从小到大枚举y,然而随着D的增大,特解中x的增长速度也是惊人的。(D=991时的最小特解y=12055735790331359447442538767,这时x=379516400906811930638014896080)这不仅需要写一个高精度乘法,而且枚举次数也是不现实的。

    好在数学家给我们提供一种更好的方法:若根号N的连分数展开为{a0;<a1,a2,...,an,2a0>},记p/q=[a0,a1,...an],则这个佩尔方程的特解就是(p,q)(D为偶数),(2p^2+1,2pq)(D为奇数时)。(关于上述符号的意义可以参见Project Euler64&65,定理的证明可以参见二潘的《初等数论》,里面用连分数理论刻画了Pell方程)感觉这道题放在这里别有深意,因为Project Euler Problem 65和Problem 64恰恰是关于连分数计算和二次根式的连分数展开的。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <malloc.h>

typedef struct {
	int fenzi;
	int fenmu;
	int k;
	int irrationalPart;
}twoReal;  // ÓÐÀíÊý+¶þ´Î¸ùʽ 

int gcd(int a,int b) {
	int da=abs(a),db=abs(b),t=da%db;
	while (t!=0) {
		da = db;
		db = t;
		t = da%db;
	}
	return db;
}

double lengthOfReal(twoReal x )
{
	double ret;
	ret = x.fenzi*1.0/x.fenmu+sqrt(x.irrationalPart)/(x.k);
	return ret;
}

twoReal jieduan(twoReal x) 
{
	twoReal ret;
	int daxiao = (int)lengthOfReal(x);
	ret.fenmu = x.fenmu;
	ret.fenzi = x.fenzi-daxiao*x.fenmu;
	ret.irrationalPart = x.irrationalPart;
	ret.k = x.k;
	return ret;
}

twoReal daoshu(twoReal x) 
{
	twoReal ret;
	int gongyue=1;
	ret.fenzi = x.k*x.k*x.fenmu*x.fenzi;
	ret.fenmu = x.k*x.k*x.fenzi*x.fenzi-x.fenmu*x.fenmu*x.irrationalPart;
	ret.k = (-x.k*x.k*x.fenzi*x.fenzi+x.fenmu*x.fenmu*x.irrationalPart)/(x.k*x.fenmu*x.fenmu);
	ret.irrationalPart = x.irrationalPart;
	gongyue = gcd(ret.fenzi,ret.fenmu);
	ret.fenzi /= gongyue;
	ret.fenmu /= gongyue;
	if (ret.fenmu<0) {
		ret.fenmu*=-1;
		ret.fenzi*=-1;
	}
	return ret;
}

int xiangdeng(twoReal a,twoReal b) {
	int ret=0;
	if (a.fenmu==b.fenmu&&a.fenzi==b.fenzi&&a.irrationalPart==b.irrationalPart&&a.k==b.k) {
		ret = 1;
	}
	return ret;
}

int chazhao(twoReal a,twoReal loop[],int length) 
{
	int ret=0;
	for (int i=0;i<length;i++) {
		if (xiangdeng(a,loop[i])) {
			ret = 1;
			break;
		}
	}
	return ret;
}

void beijia(int fenzi[],int fenmu[],int a) 
{
	int temp[500] = {0};
	for (int i=0;i<500;i++) {
		temp[i] = a*fenmu[i];
	}
	for (int i=0;i<500;i++) {
		if (temp[i]>9&&i<=498) {
			temp[i+1] += temp[i]/10;
			temp[i] %= 10;
		}
		else if (temp[i]>9) {
			printf("yichu\n");
			break;
		}
	}
	for (int i=0;i<500;i++) {
		fenzi[i]+=temp[i];
		if (fenzi[i]>9) {
			if (i==499) {
				printf("yichu");
				break;
			}
			else {
				fenzi[i+1] += fenzi[i]/10;
				fenzi[i] %= 10;
			}
		}
	}
}

void swap(int fenzi[],int fenmu[]) 
{
	int temp[500];
	for (int i=0;i<500;i++) {
		temp[i] = fenzi[i];
		fenzi[i] = fenmu[i];
		fenmu[i] = temp[i];
	}
}

int main () 
{
	twoReal loop[10000],a;
	memset(loop,0,10000*sizeof(twoReal));
	int j=2,length,cnt=0,lianfenshu[500]={0},lengthOfLoop=0,fenzia[500]={1},fenmua[500]={0},jie,mowei,max=0,weishu;
	for (int i=2;i<=1000;i++) {
		if (i==j*j) {
			j++;
			continue;
		}
		
		memset(fenzia,0,500*sizeof(int));
		memset(fenmua,0,500*sizeof(int));
		memset(loop,0,10000*sizeof(twoReal));
		memset(lianfenshu,0,500*sizeof(int));
		fenzia[0]=1;		
		a.fenmu = 1;
		a.fenzi = 0;
		a.irrationalPart = i;
		a.k = 1;
		length = 0;
		lengthOfLoop = 0;
		
		lianfenshu[lengthOfLoop++] = (int)lengthOfReal(a);
		a=jieduan(a);
		loop[length++]=a;
		while (chazhao(a,loop,length-1)==0) {
			a=daoshu(a);
			lianfenshu[lengthOfLoop++] = (int)lengthOfReal(a);
			a=jieduan(a); 
			loop[length++] = a;
		}
		
		for (int k=lengthOfLoop-2;k>=0;k--) {
			swap(fenzia,fenmua);
			beijia(fenzia,fenmua,lianfenshu[k]);
		}
		for (int k=499;k>=0;k--) {
			if (fenzia[k]) {
				weishu=k+1;
				break;
			}
		}
		
		if (!(lengthOfLoop%2)) {
			if (fenzia[weishu-1]>=7) {
				jie=2*weishu+2;
			} else if (fenzia[weishu-1]>=2)  {
				jie=2*weishu+1;
			} else jie=2*weishu;
		} else {
			jie=weishu;
		}   //¼òµ¥¹À¼Æ½âµÄλÊý 
		
		if (jie>=max) {
			printf("%d\t%d\n",jie,i);
			max=jie;
		}
		
//		if (i<=23) printf("%d\t%d\n",i,length-1);
//		if (length%2==0) cnt++;
//		if (length>=10000) printf("yichu");
	}
	printf("%d",cnt);
}

    代码贴下(这道题是用Problem64&65的代码拼起来的,所以可能不那么美观):


    

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值