传送门
题目需要求的是正方形内的点,每个点到
(
0
,
0
)
(0,0)
(0,0)的连线都有或者不存在斜率,这样的斜率不同的有多少个,包括斜率不存在
结论: G C D ( x , y ) = 1 GCD(x,y)=1 GCD(x,y)=1的为满足条件的,除此以外还有斜率为 0 0 0和斜率不存在的点
定义: k ( x , y ) k(x,y) k(x,y)表示 ( x , y ) (x,y) (x,y)到 ( 0 , 0 ) (0,0) (0,0)连线的斜率
证明:
1·对于任意一个点
(
x
,
y
)
(x,y)
(x,y),若
G
C
D
(
x
,
.
y
)
≠
1
GCD(x,.y)\neq 1
GCD(x,.y)=1,则
x
=
x
÷
G
C
D
(
x
,
y
)
x=x \div GCD(x,y)
x=x÷GCD(x,y),
y
=
y
÷
G
C
D
(
x
,
y
)
y=y\div GCD(x,y)
y=y÷GCD(x,y),此时
G
C
D
(
x
,
y
)
=
1
GCD(x,y)=1
GCD(x,y)=1,因此可以得到,对于点
(
x
,
y
)
(x,y)
(x,y) 若
G
C
D
(
x
,
y
)
≠
1
GCD(x,y)\neq 1
GCD(x,y)=1则一定存在一个点
(
x
1
,
y
1
)
(x_{1},y_{1})
(x1,y1) 满足
k
(
x
,
y
)
=
k
(
x
1
,
y
1
)
k(x,y)=k(x_{1},y_{1})
k(x,y)=k(x1,y1),因此我们只需要考虑
G
C
D
(
x
,
y
)
=
1
GCD(x,y)=1
GCD(x,y)=1的点即可
2·对于任意两个点
(
x
1
,
y
2
)
,
(
x
2
,
y
2
)
(x_{1},y_{2}),(x_{2},y_{2})
(x1,y2),(x2,y2)如果满足
x
1
≠
x
2
x_{1}\neq x_{2}
x1=x2或者
y
1
≠
y
2
y_{1} \neq y_{2}
y1=y2,则有
k
(
x
1
,
y
1
)
≠
k
(
x
2
,
y
2
)
k(x_{1},y_{1}) \neq k(x_{2},y_{2})
k(x1,y1)=k(x2,y2),即对于每一个不同的点
(
x
,
y
)
(x,y)
(x,y)满足
G
C
D
(
x
,
y
)
=
1
GCD(x,y)=1
GCD(x,y)=1都是一个不同的斜率
3·两种特殊情况, y = 0 y=0 y=0时 k ( x , 0 ) = 0 k(x, 0)=0 k(x,0)=0, x = 0 x=0 x=0时斜率不存在,需要加上这两个点
4·综上,结果应该是所有坐标中 G C D ( x , y ) = 1 GCD(x,y)=1 GCD(x,y)=1的个数 + + + 2
其实答案还是关于 y = x y=x y=x对称的,因此可以求一半 × 2 \times 2 ×2,减去对角线上的一个。其实也相当于求一个数的欧拉函数,因此可以使用埃氏筛+欧拉函数求解。
证毕。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll N;
ll arr[1100];
ll answer(ll n){
for (int i = 1; i <= n; i++){
arr[i] = i;
}
for (int i = 2; i <= n; i++){
if (arr[i] == i){
for (int j = i; j <= n; j += i){
arr[j] = arr[j] / i * (i - 1);
}
}
}
ll res = 3;
for (int i = 2; i <= n; i++)
res += arr[i] * 2;
return res;
}
int main(){
int t;
scanf("%d", &t);
for (int i = 1; i <= t; i++){
scanf("%lld", &N);
printf("%d %lld %lld\n", i, N, answer(N));
}
return 0;
}