题意:求x^2-n*y^2=1 按x排序第k大的解。
一.原理
佩尔方程:X^2-d Y^2=1,d不为完全平方数的整数,有无穷多个解
为什么d不能为完全平方数:
(x+y)(x-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;
}