[HDU3292]No more tricks, Mr Nanguo

No more tricks, Mr Nanguo

题解

板子题...

首先,我们可以枚举y(毕竟y要小些)来求出一组最小的正整数解的x,y。不会T的,毕竟y很小。

由于Pell方程有着x_{i}=x_{i-1}\cdot x_{1}+ n\cdot y_{i-1}\cdot y_{1}y_{i}= x_{i-1}\cdot y_{1} + y_{i-1}\cdot x_{1}的迭代公式,我们可以通过递推将其求出第k组解。

关于上面迭代公式的证明:

x_{i}^2+n\cdot y_{i}^2= (x_{i-1}\cdot x_{1}+ n\cdot y_{i-1}\cdot y_{1})^2+ n(x_{i-1}\cdot y_{1} + y_{i-1}\cdot x_{1})^2

             = (x_{i-1}^2\cdot x_{1}^2+n^2\cdot y_{i-1}^2\cdot y_{1}^2+ 2n\cdot x_{i-1}\cdot x_{1}\cdot y_{i-1}\cdot y_{1})- (n\cdot x_{i-1}^2\cdot y_{1}^2 + n\cdot y_{i-1}^2\cdot x_{1}^2+ 2n\cdot x_{i-1}\cdot x_{1}\cdot y_{i-1}\cdot y_{1})

                   = (x_{1}^2- n\cdot y_{1}^2)(x_{i-1}^2- n\cdot y_{i-1}^2)

\because x_{1}^2-n\cdot y_{1}^2= 1

\therefore x_{i}^2-n\cdot y_{i}^2= (x_{1}^2-n\cdot y_{1}^2)(x_{i-1}^2- n\cdot y_{i-1}^2)= x_{i-1}^2+ n\cdot y_{i-1}^2

证毕。

于是,我们又惊奇地发现上面的那个式子可以转化成矩阵快速幂求解。即:

\begin{bmatrix} x_{i}\\ y_{i} \end{bmatrix}=\begin{bmatrix} x_{1} &n\cdot y_{1} \\ y_{1} & x_{1} \end{bmatrix}\cdot \begin{bmatrix} x_{i-1} \\ y_{i-1} \end{bmatrix},于是,就可以通过矩阵快速幂求解了。

其实还可以用连分数的方法去求第1组特解,不过不知道为什么要比暴力慢一些。

源码

暴力的代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
using namespace std;
typedef long long LL;
const int mo=8191;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,k;
struct matrix{
	int n,m,c[2][2];
	matrix(){n=m=0;memset(c,0,sizeof(c));}
	matrix operator * (const matrix &rhs)const{
		matrix res;res.n=n;res.m=rhs.m;
		for(int i=0;i<n;i++)				
			for(int k=0;k<m;k++)
				for(int j=0;j<rhs.m;j++)
					(res.c[i][j]+=c[i][k]*rhs.c[k][j]%mo)%=mo;
		return res;
	}
};
matrix qkpow(matrix a,int s){
	matrix res;res.n=a.n;res.m=a.n;
	for(int i=0;i<a.n;i++)res.c[i][i]=1;
	while(s){if(s&1)res=res*a;a=a*a;s>>=1;}
	return res;
}
signed main(){
	while(scanf("%d %d",&n,&k)!=EOF){
		int t=floor(sqrt(1.0*n)),x,y=1;
		if(t*t==n){puts("No answers can meet such conditions");continue;}
		for(;;y++){x=floor(sqrt(n*y*y+1));if(x*x-n*y*y==1)break;}
		matrix A,B;
		A.n=2;A.m=1;A.c[0][0]=x;A.c[1][0]=y;
		B.n=B.m=2;B.c[0][0]=B.c[1][1]=x;B.c[1][0]=y;B.c[0][1]=n*y;
		A=qkpow(B,k-1)*A;
		printf("%d\n",A.c[0][0]);
	}
	return 0;
}

连分数的代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
using namespace std;
typedef long long LL;
const int mo=8191;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,k;
struct matrix{
	int n,m,c[2][2];
	matrix(){n=m=0;memset(c,0,sizeof(c));}
	matrix operator * (const matrix &rhs)const{
		matrix res;res.n=n;res.m=rhs.m;
		for(int i=0;i<n;i++)				
			for(int k=0;k<m;k++)
				for(int j=0;j<rhs.m;j++)
					(res.c[i][j]+=c[i][k]*rhs.c[k][j]%mo)%=mo;
		return res;
	}
};
matrix qkpow(matrix a,int s){
	matrix res;res.n=a.n;res.m=a.n;
	for(int i=0;i<a.n;i++)res.c[i][i]=1;
	while(s){if(s&1)res=res*a;a=a*a;s>>=1;}
	return res;
}
LL a[20005];
bool pell_minimum_solution(LL n,LL &x0,LL &y0){
	LL n1=(LL)sqrt((double)n),b=n1,c=1;double sq=sqrt(n);
	if(n1*n1==n)return false;int i=0;a[i++]=n1;LL p=1,q=0;
	do{
		c=(n-b*b)/c;double tmp=(sq+b)/c;
		a[i++]=(LL)(floor(tmp));b=a[i-1]*c-b;
	}while(a[i-1]!=2LL*a[0]);
	for(int j=i-2;j>=0;j--){LL t=p;p=q+p*a[j];q=t;}
	if(i&1)x0=p,y0=q;
	else x0=2ll*p*p+1LL,y0=2ll*p*q;
	return 1;
}
signed main(){
	while(scanf("%d %d",&n,&k)!=EOF){
		int t=floor(sqrt(1.0*n));
		if(t*t==n){puts("No answers can meet such conditions");continue;}
		LL x,y;bool g=pell_minimum_solution(n,x,y);
		matrix A,B;
		A.n=2;A.m=1;A.c[0][0]=x;A.c[1][0]=y;
		B.n=B.m=2;B.c[0][0]=B.c[1][1]=x;B.c[1][0]=y;B.c[0][1]=n*y;
		A=qkpow(B,k-1)*A;
		printf("%d\n",A.c[0][0]);
	}
	return 0;
}

谢谢!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值