可见的点
原题链接
题目描述
在一个平面直角坐标系的第一象限内,如果一个点 (x,y) 与原点 (0,0) 的连线中没有通过其他任何点,则称该点在原点处是可见的。
例如,点 (4,2) 就是不可见的,因为它与原点的连线会通过点 (2,1)。
部分可见点与原点的连线如下图所示:

编写一个程序,计算给定整数 N 的情况下,满足 \(0≤x,y≤N\) 的可见点 (x,y) 的数量(可见点不包括原点)。
欧拉函数
对于一个点 \((x_0, y_0)\),与原点 \((0, 0)\),构成的直线方程为 \(y=\frac{y_0}{x_0}x\)。要使点是从原点出发,沿着这条直线第一个遇到的点 \((x, y)\),那必然是
\[
\begin{cases}
x=\frac{x_0}{\gcd(x_0,y_0)}\\
y=\frac{y_0}{\gcd(x_0,y_0)}
\end{cases}
\]
即,\(\gcd(x,y)=1\)。
同时可以发现可到达的点都是对于 \(y=x\) 对称。因此右下半区内,对于横坐标x,要找到范围 \([2,x)\) 与其互质的数的数量即为 \(\varphi(x)\)。
因此 \(res=3+\sum_{i=2}^{n}\varphi(i)\)
代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 | #include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n;
int primes[N], cnt;
bool st[N];
int phi[N];
void init(int n) {
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes[cnt++] = i;
phi[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) {
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
init(1000);
cin >> n;
for (int j = 1; j <= n; j++) {
int x;
cin >> x;
int res = 3;
for (int i = 2; i <= x; i++) res += phi[i] * 2;
cout << j << ' ' << x << ' ' << res << endl;
}
return 0;
}
|