【代码超详解】CometOJ C0896 [SDOI2008]仪仗队(欧拉函数 + 思维,4 ms)

一、题目描述

1000 ms / 256 MB

作为体育委员,C 君负责这次运动会仪仗队的训练。仪仗队是由学生组成的 N×N 的方阵,为了保证队伍在行进中整齐划一,C 君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
【代码超详解】CometOJ C0896 [SDOI2008]仪仗队(欧拉函数 + 思维,4 ms)
现在,C 君希望你告诉他队伍整齐时能看到的学生人数。

二、算法分析说明与代码编写指导

【代码超详解】CometOJ C0896 [SDOI2008]仪仗队(欧拉函数 + 思维,4 ms)
设C所在位置的坐标为(0,0)。如果(x,y)能够被(0,0)直接看到,那么 x 和 y 互质。否则这个点会被(x/g,y/g)挡住,g = gcd(x, y)。即(0,0)总是和(x/g,y/g)、(x,y)在同一直线上。
令 x = 2,3,……,n - 1,并设 y ≤ x。容易发现符合条件的 y 的数量是 φ(2)、φ(3)、……、φ(n - 1)。交换 y 和 x,又有同样数量的点。再加上总是可以被看见的(0,1),(1,0),(1,1)三个点,就得到答案。

三、AC 代码(4 ms)

#include<cstdio>
#include<algorithm>
#pragma warning(disable:4996)
using namespace std;
unsigned n, s, p[40001];
unsigned prime[4792] = { 2,3 }, _PrimeTy, MaxPrime, * prime_end = prime + sizeof(prime) / sizeof(prime[0]);
inline void gen_prime() {
	decltype(_PrimeTy) a = 4, t; bool flag = true;
	for (auto i = prime + 2; i != prime_end;) {
		t = sqrt(a); flag = true;
		for (auto j = prime; *j <= t; ++j)if (a % *j == 0) { flag = false; break; }
		if (flag) { *i = a, ++i; }
		++a;
	}
	MaxPrime = *(prime_end - 1);
}
inline bool isprime(const decltype(_PrimeTy)& x) {
	if (x <= MaxPrime)return binary_search(prime, prime_end, x);
	else {
		static decltype(_PrimeTy) t; t = min((decltype(_PrimeTy))sqrt(x), MaxPrime);
		for (auto j = prime; *j <= t; ++j)if (x % *j == 0)return false;
		return true;
	}
}
template<class _Pty> inline void gen_phi(_Pty* const phi, const _Pty& n) {//质数打表的最大值至少要达到n,否则会越界
	phi[1] = 1;
	for (_Pty i = 2; i <= n; ++i) {
		if (isprime(i))phi[i] = i - 1;
		for (auto j = prime; i * *j <= n; ++j) {
			if (i % *j == 0)phi[i * *j] = *j * phi[i];
			else phi[i * *j] = (*j - 1) * phi[i];
		}
	}
}
int main() {
	scanf("%u", &n); gen_prime(); gen_phi(p, n);
	for (unsigned i = 2; i < n; ++i)s += p[i];
	printf("%u\n", 2 * s + 3);
	return 0;
}
【代码超详解】CometOJ C0896 [SDOI2008]仪仗队(欧拉函数 + 思维,4 ms)【代码超详解】CometOJ C0896 [SDOI2008]仪仗队(欧拉函数 + 思维,4 ms) 山上一缕烟 发布了231 篇原创文章 · 获赞 22 · 访问量 1万+ 私信 关注
上一篇:笔记:罗默模型


下一篇:第四十五个知识点:描述一些对抗RSA侧信道攻击的基础防御方法