题目:POJ3090.
题目大意:给定一个平面直角坐标系,每一个整点位置都插着一个钉子,问从点
(
0
,
0
)
(0,0)
(0,0)到点
(
n
,
n
)
(n,n)
(n,n)的矩阵中,从
(
0
,
0
)
(0,0)
(0,0)开始可以看到多少个钉子(不包括
(
0
,
0
)
(0,0)
(0,0)上的钉子).
原题图:
1
≤
n
≤
1
0
3
1\leq n\leq 10^3
1≤n≤103,数据组数
≤
1
0
3
\leq 10^3
≤103.
拿到题的时候感觉不是很可做,其实仔细分析一下后,会发现坐标为
(
0
,
x
)
(0,x)
(0,x)和
(
x
,
0
)
(x,0)
(x,0)的点中,只有
(
0
,
1
)
(0,1)
(0,1)和
(
1
,
0
)
(1,0)
(1,0)满足条件;
(
1
,
1
)
(1,1)
(1,1)到
(
n
,
n
)
(n,n)
(n,n)中只有
g
c
d
(
x
,
y
)
=
1
gcd(x,y)=1
gcd(x,y)=1的点才满足条件.所以答案为:
2
+
∑
i
=
1
n
∑
j
=
1
n
[
g
c
d
(
i
,
j
)
=
1
]
=
3
+
2
∑
i
=
2
n
∑
j
=
1
i
[
g
c
d
(
i
,
j
)
=
1
]
=
3
+
2
∑
i
=
2
n
ϕ
(
i
)
2+\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)=1]\\ =3+2\sum_{i=2}^{n}\sum_{j=1}^{i}[gcd(i,j)=1]\\ =3+2\sum_{i=2}^{n}\phi(i)
2+i=1∑nj=1∑n[gcd(i,j)=1]=3+2i=2∑nj=1∑i[gcd(i,j)=1]=3+2i=2∑nϕ(i)
然后问题就变成了快速求 ϕ \phi ϕ函数的和,线性筛之后在前缀和一下 ϕ \phi ϕ函数即可,时间复杂度 O ( n + C ) O(n+C) O(n+C).
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000;
int b[N+9],pr[N+9],tp;
LL phi[N+9];
void sieve(int n){
for (int i=2;i<=n;++i) b[i]=1;
phi[1]=1;
for (int i=2;i<=n;++i){
if (b[i]) pr[++tp]=i,phi[i]=i-1;
for (int j=1;j<=tp&&i*pr[j]<=n;++j){
b[i*pr[j]]=0;
if (i%pr[j]==0){
phi[i*pr[j]]=phi[i]*pr[j];
break;
}
phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
}
int n;
Abigail start(){
sieve(N);
phi[1]=0;
for (int i=2;i<=N;++i)
phi[i]+=phi[i-1];
}
Abigail into(){
scanf("%d",&n);
}
Abigail outo(int cas){
printf("%d %d %lld\n",cas,n,2*phi[n]+3);
}
int main(){
start();
int t;
scanf("%d",&t);
for (int i=1;i<=t;++i){
into();
outo(i);
}
return 0;
}