[SDOI2008] 仪仗队 题解
本题乍一看没有什么思路,但是我们不妨把样例中所有的点都列举出来:
我们按照数字从大到小的顺序把坐标排列一下(不计入重复的点):
在这些点中,一部分是被看见的,一部分未被看见,我们将未被看见的标记为“舍”:
我们可以发现,除数字 1 外,所有被 “舍” 的点中,横纵坐标都不是互质数;也就是说,除了 1 以外,只要横纵坐标互质,那么这个点就可以被看见。
这让我们不由得想到某个东西——欧拉值。
我们去掉被舍去的点:
不难看出:对于 [2, n-1] 中的每一个正整数 i ,与之相关的坐标中,被看见人数是小于 i 并与 i 互质的整数和乘2,即 φ( i ) * 2。
因此,我们只需要求出 [2, n-1] 区间所有的 欧拉值 乘 2,在最后进行一个对于 1 的特判即可了。
这里提供欧拉筛的代码:(时间复杂度:O(n log log n) )
void phi_table(int n, int* phi) {
for(int i = 2; i <= n; i++) phi[i] = 0;
phi[1] = 1;
for(int i = 2; i <= n; i++) if(!phi[i])
for(int j = i; j <= n; j += i) {
if(!phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
特判:当 n 等于 1 时,实际上已经没有任何人会被看见了,所以此时答案是0;n 大于 1 时,答案应该是欧拉值之和 加上 3.(实际上就是 (1, 1), (1, 0), (0, 1) 这三个点)。
代码奉上:
#include <iostream>
using namespace std;
const int maxn = 4e4 + 5;
int a, ans;
int phi[maxn];
void phi_table(int n, int* phi) {
for(int i = 2; i <= n; i++) phi[i] = 0;
phi[1] = 1;
for(int i = 2; i <= n; i++) if(!phi[i])
for(int j = i; j <= n; j += i) {
if(!phi[j]) phi[j] = j;
phi[j] = phi[j] / i * (i-1);
}
}
int main() {
cin >> a;
phi_table(a, phi);
for(int i = 2; i <= a-1; i++)
ans += phi[i]*2;
if(a != 1) ans += 3;
cout << ans;
return 0;
}
感谢阅读