圆上的整点 题解

题意:给定非负整数\(n\),求方程\(x^2+y^2=n\)的所有整数解(\((x,y)\)\((y,x)\)算一组解)
数据范围:\(n\le4\times 10^{18}\)
题解
根据费马平方和定理,如果 \(n\) 分解质因数后形如 \(4p+3\) 的质数的幂次为奇数那么无解
否则将 \(n\) 分解为高斯素数并暴力 DFS 枚举分配方案求解
因为\(n\)非常大所以要用 Pollard-Rho 分解质因数
对于 \(2\) 显然可以分解为 \(\left(1+i\right)\left(1-i\right)\)
对于 \(4p+1\) 类型的数可以参考这篇博客
具体方法为:

  • 用二次剩余求出 \(x_0^2\equiv-1\left(\bmod p\right)\) 的解
    (因为 \(p\)\(4p+1\) 类型的数,所以 \((-1)^{\frac{p-1}{2}}=1\),所以 \(-1\) 有二次剩余)
  • \(p\)\(x_0\) 做辗转相除,当余数小于 \(\sqrt{p}\) 的时候停止
  • 此时的 \(r\)\(\sqrt{p-r^2}\) 即为方程 \(x^2+y^2=p\) 的非负整数解
  • 证明我不会

对于 \(4p+3\) 类型的数不需要继续分解(因为无法分解)
代码如下:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define M 1000005
using namespace std;
long long P[M],num[M],R;
long long read(){
	char c=getchar();long long ans=0;
	while (c<'0'||c>'9') c=getchar();
	while (c>='0'&&c<='9') ans=ans*10+c-'0',c=getchar();
	return ans;
}
void Write(long long x){
	if (x<10) putchar(x^48);
	else Write(x/10),putchar((x%10)^48);
	return;
}
long long add(long long u,long long v,long long mod){u+=v-mod;return u+((u>>63)&mod);}
long long gcd(long long x,long long y){return y?gcd(y,x%y):x;}
long long Abs(long long x){return x>0?x:-x;}
long long mult(long long x,long long y,long long mod){
	if (x<=1000000000&&y<=1000000000) return x*y%mod;
	long long ans=x*y-(long long)((long double)(x)*y/mod)*mod;
	if (ans<0) return ans+mod;
	if (ans>=mod) return ans-mod;
	return ans;
}
long long power(long long x,long long y,long long mod){
	long long ans=1,now=x%mod;
	for (register long long i=y;i;i>>=1,now=mult(now,now,mod))
		if (i&1) ans=mult(ans,now,mod);
	return ans;
}
namespace Pollard_Rho{
	bool check(long long x,long long p){
		long long d=0,tmp=x-1;
		while (!(tmp&1)) tmp>>=1,++d;
		long long cur=power(p,tmp,x);
		if (cur==1||cur==x-1) return 1;
		while (--d) if ((cur=mult(cur,cur,x))==x-1) return 1;
		return 0;
	}
	bool is_prime(long long x){
		if (x==2ll||x==3ll||x==7ll||x==61ll||x==24251ll) return 1;
		if (x<2ll||x==46856248255981ll||!(x&1)) return 0;
		return check(x,2ll)&&check(x,3ll)&&check(x,7ll)&&check(x,61ll)&&check(x,24251ll);
	}
	long long F(long long x,long long c,long long mod){return add(mult(x,x,mod),c,mod);}
	long long get_divide(long long x){
		long long s=0,t=0,c=rand()%(x-1)+1,val=1;
		for (register int goal=1;;goal<<=1,s=t,val=1){
			for (register int step=1;step<=goal;++step){
				t=F(t,c,x),val=mult(val,Abs(t-s),x);
				if (step%127==0){
					long long d=gcd(val,x);
					if (d>1) return d;
				}
			}
			long long d=gcd(val,x);
			if (d>1) return d;
		}
		return 0;
	}
	void divide(long long x){
		if (x<2) return;
		if (is_prime(x)){P[++P[0]]=x;return;}
		long long now=get_divide(x);
		while (x%now==0) x/=now;
		divide(x),divide(now);
		return;
	}
}
namespace Sqrt{
	long long mod,I;
	bool check(long long x){return power(x,(mod-1)>>1,mod)==1;}
	struct Sqrt{
		long long x,y;
		Sqrt operator* (const Sqrt b) const{
			long long X=add(mult(x,b.x,mod),mult(mult(y,b.y,mod),I,mod),mod);
			long long Y=add(mult(x,b.y,mod),mult(y,b.x,mod),mod);
			return (Sqrt){X,Y};
		}
		Sqrt operator*= (const Sqrt &b){return *this=*this*b;}
		Sqrt operator^ (const long long b) const{
			Sqrt ans=(Sqrt){1,0},now=*this;
			for (register long long i=b;i;i>>=1,now*=now)
				if (i&1) ans*=now;
			return ans;
		}
	};
	long long get_sqrt(long long n,long long Mod){;
		mod=Mod;long long now=rand()%mod;
		while (check((mult(now,now,mod)+mod-n)%mod)) now=rand()%mod;
		I=(mult(now,now,mod)-n+mod)%mod;
		return ((Sqrt){now,1}^((mod+1)>>1)).x;
	}
}
namespace Get_ans{
	pair <int,int> ans[M<<2];
	int ans_num;
	struct Complex{
		long long X,Y;
		Complex operator* (const Complex b) const{
			return (Complex){X*b.X-Y*b.Y,X*b.Y+Y*b.X};
		}
		Complex operator*= (const Complex &b){return *this=*this*b;} 
	}B[M];
	Complex work(Complex x){return (Complex){x.X,-x.Y};}
	Complex divide_num(long long x){
		long long tmp=x,X0=Sqrt::get_sqrt(x-1,x),r=x%X0,sqrtx=(long long)(sqrt(x));
		while (r>sqrtx+3||r*r>tmp) x=X0,X0=r,r=x%X0;
		return (Complex){r,(long long)(sqrt(tmp-r*r+0.000001))};
	}
	void DFS(long long x,Complex now){
		if (x==P[0]+1){ans[++ans_num]=make_pair(min(Abs(now.X),Abs(now.Y)),max(Abs(now.X),Abs(now.Y)));return;}
		if (P[x]==2){
			for (register int i=1;i<=num[x];i++) now*=B[x];
			DFS(x+1,now);return;
		}
		if (P[x]%4==3){
			for (register int i=1;i<=(num[x]>>1);i++) now*=B[x];
			DFS(x+1,now);return;
		}
		for (register int i=0;i<=num[x];i++){
			Complex nxt=now;
			for (register int j=1;j<=i;j++) nxt*=B[x];
			for (register int j=1;j<=num[x]-i;j++) nxt*=work(B[x]);
			DFS(x+1,nxt);
		}
		return;
	}
	void solve(){
		for (register long long i=1;i<=P[0];i++){
			long long tmp=R;
			while (tmp%P[i]==0) tmp/=P[i],++num[i];
			if (P[i]==2) B[i]=(Complex){1,1};
			else if (P[i]%4==1) B[i]=divide_num(P[i]);
			else {
				if (P[i]%4==3&&(num[i]&1)){printf("No Solution");return;}
				else B[i]=(Complex){P[i],0};
			}
		}
		DFS(1,(Complex){1,0});
		sort(ans+1,ans+1+ans_num);ans_num=unique(ans+1,ans+1+ans_num)-(ans+1);Write(ans_num),putchar('\n');
		for (register int i=1;i<=ans_num;i++) Write(ans[i].first),putchar(' '),Write(ans[i].second),putchar('\n');
		return;
	}
}
int main(){
	if (!(R=read())){printf("1\n0 0");return 0;} 
	Pollard_Rho::divide(R);sort(P+1,P+1+P[0]);
	P[0]=unique(P+1,P+1+P[0])-(P+1);Get_ans::solve();
	return 0;
}
原文地址:https://www.cnblogs.com/bestlxm/p/12306878.html