题意
传送门 POJ 3090
题解
可视的点即满足 g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1 的点,因为此时在斜率为 y / x y/x y/x 的射线上,满足以其为斜边,平行于 x , y x,y x,y 轴的边为直角边的直角三角形中,直角边为整数的在射线上非原点的顶点离原点最近的点就是 ( x , y ) (x,y) (x,y)。
观察到这样的点关于
y
=
x
y=x
y=x 对称,那么仅处理
y
<
x
y<x
y<x 的部分即可,特殊处理
y
=
x
y=x
y=x 与
x
,
y
x,y
x,y 为
0
0
0 的点,即
(
0
,
1
)
,
(
1
,
0
)
,
(
1
,
1
)
(0,1),(1,0),(1,1)
(0,1),(1,0),(1,1),则答案为
2
×
∑
i
=
2
N
p
h
i
(
i
)
+
3
2\times\sum\limits_{i=2}^{N}phi(i)+3
2×i=2∑Nphi(i)+3 预处理出欧拉函数的前缀和,就可以
O
(
1
)
O(1)
O(1) 地进行查询。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 1005
int C, N, minp[maxn], prime[maxn], phi[maxn], sum[maxn];
void sieve()
{
int p = 0;
for (int i = 2; i < maxn; ++i)
{
if (minp[i] == 0)
prime[p++] = i, minp[i] = i, phi[i] = i - 1;
for (int j = 0; j < p && i * prime[j] < maxn; ++j)
{
int k = i * prime[j];
minp[k] = prime[j];
if (minp[i] == prime[j])
{
phi[k] = phi[i] * prime[j];
break;
}
else
phi[k] = phi[i] * (prime[j] - 1);
}
}
for (int i = 2; i < maxn; ++i)
sum[i] = sum[i - 1] + phi[i];
}
int main()
{
sieve();
scanf("%d", &C);
for (int i = 1; i <= C; ++i)
{
scanf("%d", &N);
printf("%d %d %d\n", i, N, 2 * sum[N] + 3);
}
return 0;
}