先考虑素数 的平方和:
当
时,显然只有唯一解
;
当
时,显然无解,因为任何数的平方模
只可能为
;
当
时,由于此时
必然是
的二次剩余,设
,有:
注意到
,而
和
显然不满足这种形式,所以
的因子同时存在于他们之中,即
不是高斯素数。则:
因为
是素数,所以:
故此时
能够成为两个数的平方和,同时这一对数唯一且共轭,否则将与唯一分解定理相悖。
接着考虑合数的平方和:
我们直接将
写成高斯素数的分解形式,那么:
当
时,
;
当
时,用之前的分析方式可以发现其一定是高斯素数,即
;
当
时,
。
即:
注意到如果
,那么
,即
的一对共轭因数。那么我们将其中一个因数写出来:
接着将他的共轭写出来(
):
可以发现,为了满足条件,
和
已经确定了,他们必须为
和
,所以
,即模
余
的素数的幂必须为偶数。剩下的可选项只有
,注意到他们必须满足
,即
种选择,所以我们可以得到
的二平方和的方案数(非本质不同)为
。而对于求所有解,只需要将
分解之后对
暴力即可。
那么还需要解决的问题就是求出
时的二平方和的解,继续设
,那么我们有:
考虑将
减少,并同时保持左边的平方和合法。我们将在处理的式子当作:
那么设:
有:
注意到:
最终有:
因为
,所以:
由此,我们可以在
下求出
的一组解。
最后计算一下暴力产生的复杂度,考虑最坏情况,即
都由模
余
的素数组成时,
,但对于满足条件的素数,这个界是非常松的:
由
,知道前20个模
余
的素数的积必然大于
,同时我们知道,对于给定的
,当
时,
得到最大值,同时显然的,最大因子数随幂数和递增,于是我们计算幂数和为
时的最大因子数,即
。所以由模
余
的素数组成的不大于
的数的因子数不会超过
,当然实际的值会比这个值小很多。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
//--Container
//--
typedef __int128 ll;
ll qni(ll a,ll b,ll md){
ll r=1;for(;b;b>>=1,a=a*a%md)if(b&1)r=r*a%md;
return r;
};
ll _P,_W;
struct vt{
ll a,b;
vt(ll _a=0,ll _b=0):a(_a),b(_b){};
friend vt operator*(vt&,vt&);
};
vt operator*(vt&a,vt&b){
return vt((a.a*b.a+_W*a.b%_P*b.b)%_P,(a.a*b.b+a.b*b.a)%_P);
};
vt vqni(vt a,ll b){
vt r(1,0);for(;b;b>>=1,a=a*a)if(b&1)r=r*a;
return r;
};
inline ll _ck(ll n){n%=_P;return (n+_P)%_P;};
ll _xq(ll x,ll n){
if(qni(x,(n-1)>>1,n)==n-1)return -19260817;
ll t;for(_P=n;;){
t=rand();if(qni(_ck(t*t-x),(n-1)>>1,n)==n-1)break;
}
_W=_ck(t*t-x);
return vqni(vt(t,1),(n+1)>>1).a;
};
struct vi{
ll a,b;
vi(ll _a=0,ll _b=0):a(_a),b(_b){};
friend vi operator*(vi,vi);
};
vi operator*(vi a,vi b){
return vi(a.a*b.a-a.b*b.b,a.a*b.b+a.b*b.a);
};
void _dss(ll&a,ll&b,ll m){
ll x,y,t,k,d;for(;m>1;){
x=a%m,y=b%m;
if(x>m/2)x-=m;
if(y>m/2)y-=m;
k=(x*x+y*y)/m;
d=(a*x+b*y)/m,t=(a*y-b*x)/m;
m=k,a=d,b=t;
}
};
void _p1s(ll p,ll&a,ll&b){
ll t=_xq(p-1,p);int i,j,k,d;
_dss(a=t,b=1,(t*t+1)/p);
};
//--TEMPLATE
const int S=2;
ll mult_mod(ll a,ll b,ll c)
{
a%=c;
b%=c;
ll ret=0;
while(b)
{
if(b&1){ret+=a;ret%=c;}
a<<=1;
if(a>=c)a%=c;
b>>=1;
}
return ret;
}
ll pow_mod(ll x,ll n,ll mod)
{
if(n==1)return x%mod;
x%=mod;
ll tmp=x;
ll ret=1;
while(n)
{
if(n&1)ret=mult_mod(ret,tmp,mod);
tmp=mult_mod(tmp,tmp,mod);
n>>=1;
}
return ret;
}
ll check(ll a,ll n,ll x,ll t)
{
ll ret=pow_mod(a,x,n);
ll last=ret;
for(int i=1;i<=t;i++)
{
ret=mult_mod(ret,ret,n);
if(ret==1 && last!=1 &&last!=n-1)return true;
last=ret;
}
if(ret!=1)return true;
return false;
}
bool Miller_Rabin(ll n)
{
if(n<2)return false;
if(n==2)return true;
if((n&1)==0)return false;
ll x=n-1;
ll t=0;
while((x&1)==0){x>>=1;t++;}
for(int i=0;i<S;i++)
{
ll a=rand()%(n-1)+1;
if(check(a,n,x,t))
return false;
}
return true;
}
ll factor[100];
int tol;
ll gcd(ll a,ll b)
{
if(a==0)return 1;
if(a<0)return gcd(-a,b);
while(b)
{
ll t=a%b;
a=b;
b=t;
}
return a;
}
ll Pollard_rho(ll x,ll c)
{
ll i=1,k=2;
ll x0=rand()%x;
ll y=x0;
while(1)
{
i++;
x0=(mult_mod(x0,x0,x)+c)%x;
ll d=gcd(y-x0,x);
if(d!=1&&d!=x)return d;
if(y==x0)return x;
if(i==k)
{
y=x0;
k+=k;
}
}
}
void findfac(ll n)
{
if(Miller_Rabin(n))
{
factor[tol++]=n;
return;
}
ll p=n;
while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
findfac(p);
findfac(n/p);
}
//--https://www.cnblogs.com/kuangbin/archive/2012/11/11/2765525.html
int sm[70],pn;vi vr[70][70];ll n;
vi rss[1000010];int rsn;
vi _cl(bool&fg){
int i,j,k,d,t;vi rs(1,0);ll a,b,dn=n,qs;for(pn=i=0;i<tol;++i){
for(qs=1,d=0;!(dn%factor[i]);dn/=factor[i],++d);
if(factor[i]==2){
vi tz(1,0);for(j=0;j<d;++j)tz=tz*vi(1,1);
rs=rs*tz;
}
else if(factor[i]%4==3){
if(d&1){fg=0;return vi(19260817,19260817);}
for(qs=1,j=0;j<(d>>1);++j,qs*=factor[i]);
rs=rs*vi(qs,0);
}
else{
sm[pn]=d;vi tz(1,0);_p1s(factor[i],a,b);for(j=d;j>=0;--j,tz=tz*vi(a,-b))
vr[pn][j]=tz;
for(tz=vi(1,0),j=0;j<=d;++j,tz=tz*vi(a,b))
vr[pn][j]=vr[pn][j]*tz;
++pn;
}
}
return rs;
};
void dfs(int d,vi rs){
if(d==pn){rss[rsn++]=rs;return;}
int i;for(i=0;i<=sm[d];++i){
dfs(d+1,rs*vr[d][i]);
}
};
bool vimp(const vi&a,const vi&b){
return a.a==b.a?a.b<b.b:a.a<b.a;
};
void _sca(ll&n){
n=0;char t;for(t=getchar();t<'0'||t>'9';t=getchar());
n=t-'0';for(t=getchar();t>='0'&&t<='9';t=getchar())
n=n*10+t-'0';
};
void _prt(ll n){
if(n>9)_prt(n/10);
putchar(n%10+'0');
};
void cl(){
int i,j,k;_sca(n);findfac(n);
sort(factor,factor+tol);tol=unique(factor,factor+tol)-factor;
bool fg=1;vi rs=_cl(fg);
if(!fg)printf("No Solution\n");
else{
rsn=0;dfs(0,rs);
for(i=0;i<rsn;++i){
rss[i].a=abs(rss[i].a),rss[i].b=abs(rss[i].b);
if(rss[i].a>rss[i].b)swap(rss[i].a,rss[i].b);
}
for(sort(rss,rss+rsn,vimp),i=0;i<rsn;i=j){
for(j=i+1;j<rsn&&rss[i].a==rss[j].a&&rss[i].b==rss[j].b;++j);
_prt(rss[i].a);putchar(' ');_prt(rss[i].b);putchar('\n');
}
}
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
cl();
return 0;
};