目录
HDU1017——A Mathematical Curiosity
HDU1019——Least Common Multiple
HDU1017——A Mathematical Curiosity
题目描述
运行代码
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n, m, c = 0, num = 0;
while (cin >> n >> m && (n || m)) {
c = 0;
for (int i = 1; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (((i * i + j * j + m) % (i * j)) == 0) {
c++;
}
}
}
cout << "Case " << ++num << ": " << c << endl;
}
if (t) {
cout << endl;
}
}
return 0;
}
代码思路
-
输入处理:
- 首先读入一个整数
t
,表示测试用例的数量。 - 接下来,对于每个测试用例,读入两个整数
n
和m
。
- 首先读入一个整数
-
循环计算:
- 对于每个测试用例,使用两层嵌套循环来枚举所有可能的整数对ii和jj(其中1 \leq i < j < n1≤i<j<n)。
- 在内部循环中,检查(i^2 + j^2 + m)(i2+j2+m)是否能被(i \times j)(i×j)整除,如果是,则增加计数器
c
。
-
输出结果:对于每个测试用例,输出符合条件的整数对的数量,并以“Case X: Y”的格式显示,其中X是测试用例的编号(从1开始),Y是该测试用例的结果。
-
测试用例间隔:如果还有剩余的测试用例,那么在输出完一个测试用例的结果后,会额外输出一个空行作为分隔。
HDU1018——Big Number
题目描述
运行代码
#include <cmath>
#include <iostream>
using namespace std;
const float M_PI = 3.141592653589793;
const float M_E = 2.718281828459045;
double stirling(double n) {
return log10(sqrt(2 * M_PI * n)) + n * log10(n / M_E);
}
int numDigits(int n) {
double num = stirling(n);
return floor(num) + 1;
}
int main() {
int n, c;
cin >> c;
while (c--) {
cin >> n;
cout << numDigits(n) << endl;
}
return 0;
}
代码思路
-
引入头文件:
<cmath>
和<iostream>
分别用于数学函数和输入输出操作。 -
常量定义:定义了圆周率\piπ和自然对数底ee的近似值,这些常量用于斯特林公式的计算。
-
stirling 函数:此函数接受一个双精度浮点数参数nn,返回斯特林公式计算出的\log_{10}(n!)log10(n!)的近似值。斯特林公式表达式为 \log_{10}(n!) \approx \frac{1}{2}\log_{10}(2\pi n) + n\log_{10}(\frac{n}{e})log10(n!)≈21log10(2πn)+nlog10(en)。
-
numDigits 函数:此函数接受一个整数参数nn,调用
stirling
函数得到\log_{10}(n!)log10(n!)的近似值,然后取其整数部分加一,得到n!n!的位数。 -
主函数 main:
- 首先读入一个整数cc,表示将要处理的测试用例的数量。
- 然后对于每个测试用例,读入一个整数nn,调用
numDigits
函数计算并输出n!n!的位数。 - 循环直到所有测试用例都被处理完毕。
斯特林公式提供了一种有效的方法来估计大数阶乘的大小,尤其是当直接计算阶乘变得不可行时。通过计算阶乘的对数,可以避免大数运算中的溢出问题,并且可以快速得出阶乘的位数。
斯特林公式
HDU1019——Least Common Multiple
题目描述
错误代码
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int lcm(int a, int b) {
return a * b / gcd(a, b);
}
int main() {
int cases;
cin >> cases;
while (cases--) {
int num;
cin >> num;
int res = 1;
int n;
for (int i = 0; i < num; ++i) {
cin >> n;
res = lcm(res, n);
}
cout << res << endl;
}
return 0;
}
运行代码
#include <iostream>
using namespace std;
int gcd(int a, int b) { // 求 a,b 的最大公约数
return b == 0 ? a : gcd(b, a % b);
}
int main() {
int m;
cin >> m;
while (m--) {
int n, x, y;
cin >> n >> x; // 先输入第一个数字
for (int i = 1; i < n; i++) {
cin >> y;
// x 先除以最大公约数再乘 y 是为了防止溢出
x = x / gcd(x, y) * y; // 将 x 更新为 x 与 y 的最小公倍数
}
cout << x << endl;
}
return 0;
}
代码思路
-
gcd函数:这是一个递归函数,用于计算两个整数的最大公约数(Greatest Common Divisor, GCD)。它使用欧几里得算法,根据辗转相除法计算最大公约数。当
b
为0时,返回a
,否则递归调用自身,将a
替换为b
,将b
替换为a % b
。 -
main函数:
- 首先读取测试用例的数量
m
。 - 对于每一个测试用例,读取整数的数量
n
,以及第一个整数x
。 - 然后通过一个循环读取剩下的
n-1
个整数,并使用gcd
函数计算当前x
和新读取的整数y
的最大公约数,接着更新x
为x
和y
的最小公倍数。- 计算最小公倍数的过程是这样的:
x
先除以x
和y
的最大公约数,然后乘以y
。这是因为在数学上,两个数的最小公倍数等于这两个数的乘积除以它们的最大公约数,即LCM(a, b) = (a*b) / GCD(a, b)
。为了避免整数溢出,先除后乘。
- 计算最小公倍数的过程是这样的:
- 最后输出这一组整数的最小公倍数。
- 首先读取测试用例的数量
整个程序通过递归计算最大公约数和逐步计算最小公倍数的方式,有效地处理了多组数据的计算需求。这种方式适用于计算较大数目的整数的最小公倍数,同时避免了直接计算大数乘积可能导致的溢出问题。