B4077 [CSP-X2019 山东] 鼓掌
欢迎报名洛谷网校,期待和大家一起进步!
本题考查数论。
(超时做法) 使用循环结构,让变量
参考代码(部分):
for (int i = 1; i <= n; i++) {
if (i % x == 0 || i % y == 0)
cnt++;
}
这样的代码会 TLE(超时),是因为题目中的
(正确做法)
我们可以使用数学方式统计有多少秒鼓掌。
在 n / x(
在
但是,A 班和 B 班会有重叠的鼓掌时间,重叠的周期即为
因此,额外减去
最大公约数如何求出呢?有三种做法。
- 第一种做法是编写一个循环,让循环变量
z从x 和y 中的最小值开始不断自减,逐个判断是否能够同时满足x % z == 0和y % z == 0,若能满足则第一个被发现的z 就是最大公约数。这种做法效率最慢,但是足以通过本题。 - 第二种做法是使用辗转相除法,利用性质
\gcd(x,y)=\gcd(y,x \bmod y) 进行递归,从而快速计算出最大公约数,运算效率比第一种做法快。 - 第三种做法是使用库函数
__gcd(x, y)(仅限 G++ 编译器)或者std::gcd(x, y)(仅限 C++17 以后的语言标准,头文件为numeric)计算,这个做法效率上和第二种做法可以认为是一致的,但是正式赛无法使用std::gcd(x, y)。
参考代码:
int gcd(int x, int y) { //第一种做法
int z = min(x, y);
while (!(x % z == 0 && y % z == 0))
z--;
return z;
}
int gcd(int x, int y) { //第二种做法
return !y ? x : gcd(y, x % y);
}
cout << n / x + n / y - n / (x / gcd(x, y)*y) << endl;