博客背景
Добрый день! 大家好,我是Zac,太久没更文章了(毕竟假期出去玩了)。
这不是马上要考五级了吗,我回到了新手村,又看了一道我去年做5级的题,突然发现我之前的解法看——不——懂!于是呃我准备再写一版……先来看看题目吧~
题目描述
小杨的班级里共有 n 名同学,每位同学都有各自的锻炼习惯。具体来说,第 i 位同学每隔 ai 天就会进行一次锻炼(也就是说,每次锻炼会在上一次锻炼的 ai 天后进行)。某一天,班上的 n 名同学恰好都来进行了锻炼。他们对此兴奋不已,想要计算出下一次所有同学都来锻炼,至少要过多少天。但他们不会计算,你能帮帮他们吗?
输入格式
第一行一个整数 n,表示同学的数量。
第二行 n 个用空格隔开的正整数,依次为 a0,a1,…,an−1。
输出格式
输出一个整数,表示下一次所有同学都来锻炼,至少要过多少天。
输入输出样例
输入#1
3
1 2 3
输出#1
6
输入#2
4
2 4 8 16
输出#2
16
输入#3
4
2 4 6 8
输出#3
24
分析
题目分析
首先,先看题目:“某一天,班上的 n 名同学恰好都来进行了锻炼。他们对此兴奋不已,想要计算出下一次所有同学都来锻炼,至少要过多少天。” 这句话非常清楚地告诉了我们这道题的题意:这道题目的目标是计算多个同学锻炼周期的最小公倍数(LCM),即下一次所有同学再次同一天锻炼所需的最少天数。每个同学的锻炼周期由输入的数组给出。
我们接着分析题目:
-
问题转化:题目要求找到所有同学锻炼周期的最小公倍数。当所有同学在同一天锻炼后,下一次共同锻炼的天数即为这些周期的最小公倍数。
-
数学基础:两个数的最小公倍数可以通过它们的乘积除以最大公约数(GCD)得到。对于多个数的情况,可以逐个计算累积的LCM。
-
算法选择:使用欧几里得算法计算GCD,然后通过逐次计算每两个数的LCM来累积得到所有数的LCM。
思路分析
-
初始化LCM:从第一个同学的锻炼周期开始,初始LCM设为第一个数。
-
逐次计算:对于后续每个同学的周期,计算当前LCM与该周期数的GCD,然后用这两个数的乘积除以GCD来更新LCM。
-
累积结果:最终累积的LCM即为所有同学周期的LCM,即答案。
根据这些,我们直接
上代码:
强迫症版:
#include <iostream>
#include <cmath>
using namespace std;
int f(int a, int b) {
return b == 0 ? a : f(b, a % b);
}
int main() {
int n;
cin >> n;
int a[n + 1];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int sum = a[0];
for (int i = 1; i < n; i++) {
int t = sum;
sum = f(sum, a[i]);
sum = sum * (t / sum) * (a[i] / sum);
}
cout << sum << endl;
return 0;
}
懒人版:
#include<iostream>
#include<cmath>
using namespace std;
int f(int a,int b){
return b==0?a:f(b,a%b);
}
int main(){
int n;
cin>>n;
int a[n+1];
for(int i=0;i<n;i++) cin>>a[i];
int sum=a[0];
for(int i=1;i<n;i++){
int t=sum;
sum=f(sum,a[i]);
sum=sum*(t/sum)*(a[i]/sum);
}
cout<<sum<<endl;
return 0;
}
代码解析
-
输入处理:读取同学数量
n
和他们的锻炼周期数组a
。 -
计算GCD:使用递归函数
f
(即欧几里得算法)计算两个数的GCD。 -
计算LCM:遍历数组,依次计算当前LCM与下一个数的LCM,并更新结果。
-
输出结果:最终的LCM即为所求天数。
复杂度分析
-
时间复杂度:O(n log a_max),其中
a_max
是数组中最大的数。每次计算GCD的时间复杂度为O(log a_max),需要遍历n个数。 -
空间复杂度:O(n)存储输入数组,递归栈深度不影响整体复杂度。
总结
通过逐次计算每两个数的最小公倍数,并累积结果,可以高效地求解多个数的最小公倍数。使用欧几里得算法计算GCD,保证了算法的高效性。该方案正确处理了所有可能的输入情况,包括大数运算,确保结果正确。对了,点个三连再走呗~