宣传一下 算法提高课整理
CSDN个人主页:更好的阅读体验
原题链接
题目描述
在一个平面直角坐标系的第一象限内,如果一个点 $(x,y)$ 与原点 $(0,0)$ 的连线中没有通过其他任何点,则称该点在原点处是可见的。
例如,点 $(4,2)$ 就是不可见的,因为它与原点的连线会通过点 $(2,1)$。
部分可见点与原点的连线如下图所示:
编写一个程序,计算给定整数 $N$ 的情况下,满足 $0 \le x,y \le N$ 的可见点 $(x,y)$ 的数量(可见点不包括原点)。
输入格式
第一行包含整数 $C$,表示共有 $C$ 组测试数据。
每组测试数据占一行,包含一个整数 $N$。
输出格式
每组测试数据的输出占据一行。
应包括:测试数据的编号(从 $1$ 开始),该组测试数据对应的 $N$ 以及可见点的数量。
同行数据之间用空格隔开。
数据范围
$1 \le N,C \le 1000$
输入样例:
4
2
4
5
231
输出样例:
1 2 5
2 4 13
3 5 21
4 231 32549
思路
首先我们考虑在 $(0,0)$ 位置上不能看见点 $(x,y)$ 的条件为 $\gcd(x,y) \not= 1$
所以整个图能看见的点的数量为
$$\sum_{i=0}^{n}\sum_{j=0}^{n}[\gcd(i,j) = 1]$$
由于整个图形关于 $y=x$ 对称,所以我们只要统计上面一半(或下面)然后把答案 $\times 2+1$即可。
所以上面的式子化简为:
$$2 \times \sum_{i=0}^{n}\sum_{j=0}^{i}[\gcd(i,j)=1] + 1$$
这里我们引入 欧拉函数【$\varphi(n)$】 的概念:
对于正整数n,欧拉函数是小于n的正整数中与n互质的数的数目.
即:对于 $n \in \mathbb{N^*}$,$$\varphi(n)=\sum_{i=1}^{n}[\gcd(i,n)=1]$$
所以答案可简化为:
$$2 \times \sum_{i=0}^{n}\varphi(i) +1$$
我们线性预处理 $1 \sim 10^3$ 的欧拉函数,然后直接进行计算即可。
算法时间复杂度 $O(10^3+\sum N)$
线性筛欧拉函数时间复杂度为 $O(10^3)$;
对于每一个输入的 $N$,时间复杂度都是 $O(N)$。
因次总时间复杂度为 $O(10^3+\sum N)$。
最后不要忘了开 long long
。
AC Code
$\text{C}++$
#include <iostream>
#define int long long
using namespace std;
const int N = 1010;
int n, c;
int primes[N], cnt;
int euler[N];
bool st[N];
void get_eulers(int n)
{
euler[1] = 1;
for (int i = 2; i <= n; i ++ )
{
if (!st[i])
{
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ )
{
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0)
{
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
}
main()
{
scanf("%lld", &c);
get_eulers(N - 1);
for (int _ = 1; _ <= c; _ ++ )
{
scanf("%lld", &n);
int res = 0;
for (int i = 0; i <= n; i ++ )
res += euler[i];
printf("%lld %lld %lld\n", _, n, 2 * res + 1);
}
return 0;
}
最后,如果觉得对您有帮助的话,点个赞再走吧!