较为简单的思路
打表观察
a
,
b
,
c
a,b,c
a,b,c三个数的特征,发现可以表示成
i
,
p
,
q
i,p,q
i,p,q三个数相乘的形式:
a
=
i
∗
p
,
b
=
i
∗
q
,
c
=
p
∗
q
a=i*p,b=i*q,c=p*q
a=i∗p,b=i∗q,c=p∗q。
那么
g
c
d
(
a
,
b
,
c
)
=
=
1
gcd(a,b,c)==1
gcd(a,b,c)==1就可以转化成
(
先
假
设
p
,
q
两
者
互
质
)
:
i
与
p
∗
q
互
质
,
即
i
与
p
,
q
分
别
互
质
(先假设p,q两者互质):i与p*q互质,即i与p,q分别互质
(先假设p,q两者互质):i与p∗q互质,即i与p,q分别互质
现在讨论
p
,
q
两
者
不
互
质
的
情
况
:
g
c
d
(
a
,
b
,
c
)
=
g
c
d
(
p
∗
q
,
i
∗
g
c
d
(
p
,
q
)
)
,
显
然
不
等
于
一
p,q两者不互质的情况:gcd(a,b,c)=gcd(p*q,i*gcd(p,q)),显然不等于一
p,q两者不互质的情况:gcd(a,b,c)=gcd(p∗q,i∗gcd(p,q)),显然不等于一
所以我们有了新的结论:
i
,
p
,
q
三
者
必
须
互
质
。
i,p,q三者必须互质。
i,p,q三者必须互质。
然后我们从
a
,
b
,
c
a,b,c
a,b,c的角度再考虑一下
i
,
p
,
q
i,p,q
i,p,q三者的其它关系:
b
=
a
∗
c
c
−
a
,
即
i
∗
q
=
i
∗
p
∗
p
∗
q
p
∗
(
q
−
i
)
,
约
分
后
可
得
q
−
i
=
p
b=\frac{a*c}{c-a},即i*q=\frac{i*p*p*q}{p*(q-i)},约分后可得q-i=p
b=c−aa∗c,即i∗q=p∗(q−i)i∗p∗p∗q,约分后可得q−i=p
于是我们考虑对于一个确定的
n
n
n,如何得知在
c
=
=
n
c==n
c==n时合法的方案数和最小的
a
a
a:枚举
c
的
因
子
作
为
p
c的因子作为p
c的因子作为p,然后直接计算
c
/
p
=
q
,
q
−
i
=
p
c/p=q,q-i=p
c/p=q,q−i=p。
这样就有了通过题目的理论(我不是很确定枚举质因子的理论复杂度,不过应该是接近
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn))
不过此时并不足以通过本题,第一个优化是
p
一
定
小
于
q
p一定小于q
p一定小于q
然后是一个足以通过本题的优化(具体证明该优化给程序的复杂度带来怎样的变化有点麻烦,不过以笔者的感觉是提速了100%):
即然
p
,
q
p,q
p,q互质,那么枚举因子就只需枚举哪些质因子属于
p
p
p,剩下的属于
q
q
q。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
inline char nc(){
static char buf[100005],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int n,t,ans2[maxn],ans[maxn],pr[maxn],cnt,mi[maxn];
int pri[maxn],vis[maxn],num;
const int l=2e6;
void get(){
for(int i=2;i<=l;i++){
if(!vis[i]){pri[++num]=i;}
for(int j=1;i*pri[j]<=l&&j<=num;j++){
vis[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
}
inline int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void dfs(int i,int p,int c){
if(i==cnt+1){
int q=c/p;
int i=q-p;
int a=i*p,b=i*q,g=i;
if(gcd(g,c)!=1)return;
ans[c]++;
if(!ans2[c]){ans2[c]=a;}
else ans2[c]=min(ans2[c],a);
return ;
}
long long now=p;
for(int j=1;j<=mi[i];j++){
now=now*pr[i];
if(now*now>c){dfs(i+1,p,c);return ;}
}
dfs(i+1,p,c);
dfs(i+1,now,c);
}
signed main(){
//freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
get();
t=read();
const int x=2000000;
for(int c=2;c<=x;c++){
ans[c]=ans[c-1];
cnt=0;
int tmp=c;
for(int k=1;pri[k]*pri[k]<=tmp;k++){
int j=pri[k];
if(tmp%j==0){
cnt++;pr[cnt]=j;mi[cnt]=0;
while(tmp%j==0){mi[cnt]++;tmp/=j;}
}
}
if(tmp!=1){pr[++cnt]=tmp;mi[cnt]=1;}
dfs(1,1,c);
}
while(t--){
n=read();
if(n==1)puts("0");
else printf("%d %lld\n",ans[n],1ll*ans2[n]*n/(n-ans2[n]));
}
}