HDU 3292 佩尔方程入门+矩阵快速幂--你想解二元二次方程吗?

题意:求x^2-n*y^2=1 按x排序第k大的解。

一.原理

佩尔方程:X^2-d Y^2=1,d不为完全平方数的整数,有无穷多个解

为什么d不能为完全平方数:

(x+\sqrt{d}y)(x-\sqrt{d}y)=1

x只能取正负1,y取0,就不会有无穷多组解

递推式如下:

于是构造矩阵:

 

二.具体实现:

①search():

 x1,y1可以暴力解得,因为以x排序,x与y正相关,所以找最小的x,y从1开始枚举,找到第一个x即为最小

②注意判断N是否是完全平方数

③矩阵快速幂细节:

设个结构体,方便定义多个二维数组,比如单位矩阵,答案矩阵

矩阵相乘里面就要%,不单单只是快速幂那里%

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll M=(ll)8191 ;
const ll MAXN=(ll)4;
typedef struct
{
	ll m[MAXN][MAXN];  //后面要构建一堆矩阵 
}Ma;
Ma pre,a;
ll x,y,N;

void search()//找出第一个解x,y,暴力 
{
	y=1;
	while(1)
	{
		x=(long long)sqrt(N*y*y+1);
		if(x*x-N*y*y==1)break;
		y++;
		
	}
 } 

void init()//用xy初始化第一个矩阵 
{
	a.m[0][0]=x%M;
	a.m[0][1]=N*y%M;
	a.m[1][0]=y%M;
	a.m[1][1]=x%M;
	pre.m[0][0]=pre.m[1][1]=1;
	pre.m[0][1]=pre.m[1][0]=0;
}

Ma multi(Ma p,Ma q)
{
	Ma c;
	for(int i=0;i<2;i++)
	  for(int j=0;j<2;j++)
	  {
	     c.m[i][j]=0;//一定要初始化 
	    for(int k=0;k<2;k++)
	    {
	    	c.m[i][j]+=p.m[i][k]*q.m[k][j];
		}
		c.m[i][j]%=M;//一定要% 
	}
		
		
		return c;
}

Ma power(ll k)
{
	Ma c=a;
	Ma ans=pre;
	while(k)
	{
		if(k&1)  //先特殊处理奇数 
		{
			ans=multi(ans,c);
			k--;
		}
		k/=2;
		c=multi(c,c);
	}
	
	return ans;
}

int main()
{
  ll K;
  while(cin>>N>>K)
  {
  	if((ll)sqrt(N)*(ll)sqrt(N)==N)//是完全平方
	  {
	  	printf("No answers can meet such conditions\n");
         continue;
	   } 
	   search();
	   init();
	   a=power(K-1);
	   x=(a.m[0][0]*x%M+a.m[0][1]*y%M) %M;    //再乘剩下那个矩阵
	   y=(a.m[1][0]*x%M+a.m[1][1]*y%M)%M;
	   printf("%lld\n",x); 
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/zjyang12345/article/details/89006816
今日推荐