题意
在第一象限,每个点和原点有连线,给N*N大小,求解线的数量
解析
g
c
d
(
x
,
y
)
=
m
gcd(x,y)=m
gcd(x,y)=m 可以分解为
m
∗
g
c
d
(
x
,
y
)
=
1
m*gcd(x,y)=1
m∗gcd(x,y)=1; 因此斜率肯定相同,会重复。所以只要统计
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1 的个数。
现在的问题转化成,
0
<
=
x
<
=
N
,
0
<
=
y
<
=
N
0<=x<=N , 0<=y<=N
0<=x<=N,0<=y<=N 求解
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1 的个数。
我们枚举x从1~N,求解
(
1
<
=
y
<
=
x
)
g
c
d
(
x
,
y
)
=
1
(1<=y<=x) gcd(x,y)=1
(1<=y<=x)gcd(x,y)=1的个数,根据欧拉函数其值为
ϕ
(
x
)
\phi(x)
ϕ(x),我们要考虑一下中间的对角线,因此最终答案为
∑
x
=
1
N
ϕ
(
x
)
+
1
\sum_{x=1}^{N}\phi(x)+1
∑x=1Nϕ(x)+1
所以考虑筛法,在筛选的过程之中计算之和,预处理,最后通过O(1)输出。
代码
#include <iostream>
const int N=1005;
typedef long long ll;
using namespace std;
int phi[N]={0,1};
ll sum[N]={0,1};
int p[N],cnt;
int main()
{
int n;
cin>>n;
for(int i=2;i<=N;i++){
if(phi[i]==0)p[++cnt]=i,phi[i]=i-1;
for(int j=1;1ll*p[j]*i<=N;j++){
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*phi[p[j]];
}
sum[i]=sum[i-1]+phi[i];
}
for(int i=1;i<=n;i++){
int s;
cin>>s;
cout<<i<<" "<<s<<" "<<sum[s]*2+1<<endl;
}
}