abc 253 题解
D - FizzBuzz Sum Hard
题目大意:
请找出从 \(1\) 到 \(N\) 中不为 \(A\) 或 \(B\) 的倍数的数之和。
题解
我们知道,\(A\) 的 \(1\) 倍是 \(A \times 1\), \(A\) 的 \(2\) 倍是 \(A \times 2\), \(A\) 的 \(3\) 倍是 \(A \times 3\), 以此类推。
所以在 \(1\) 到 \(N\) 之间 \(A\) 的倍数的和为:\(A \times 1\) + \(A \times2\) + ...... + \(A \times (N \div A)\),提取公因数后为:\(A \times (1 + 2 + ...... + N \div A)\),可简化为:\(A \times (N \div A) \times (N \div A + 1) \div 2\)。
\(B\) 同上。
但是,有的数既是 \(A\) 的倍数,又是 \(B\) 的倍数,所以得把\(A\) 和 \(B\) 的公倍数排除出来,算法同上。
介绍一下 \(O(\log n)\) 求最大公因数和最小公倍数的算法
欧几里得算法:
gcd:最大公因数, \(\gcd(a, b) = \gcd(b, a \mod b)\)
lcm:最小公倍数, \(lcm(a, b) = a \times b \div \gcd(a, b)\)
最小公倍数的代码也贴一下吧(欧几里得算法):
long long gcd(long long a, long long b) { // 最大公因数
if (a % b == 0) {
return b;
} else {
return gcd(b, a % b);
}
}
long long lcm(long long a, long long b) { // 最小公倍数
return a * b / gcd(a, b);
}
最后贴个代码
#include <iostream>
using namespace std;
long long n, a, b, ans;
long long gcd(long long a, long long b) {
if (a % b == 0) {
return b;
} else {
return gcd(b, a % b);
}
}
long long lcm(long long a, long long b) {
return a * b / gcd(a, b);
}
int main() {
cin >> n >> a >> b;
long long ans_1 = n / a, ans_2 = n / b, ans_3 = n / lcm(a, b);
ans = (1 + n) * n / 2;
long long sum1 = a * (1 + ans_1) * ans_1 / 2;
long long sum2 = b * (1 + ans_2) * ans_2 / 2;
if (lcm(a, b) <= n) {
long long sum3 = lcm(a, b) * (1 + ans_3) * ans_3 / 2;
ans = ans - sum1 - sum2 + sum3;
} else {
ans = ans - sum1 - sum2;
}
cout << ans;
return 0;
}
不喜勿喷,谢谢