今天我们将在豆包MarsCode AI刷题平台上,完成《最小操作数使数组变为 Firm 数组》与《小C的数字倍数问题》这两个算法问题,通过这些练习提升用户解决此类问题的能力
《最小操作数使数组变为 Firm 数组》题面如下:
题目要求将一个数组 A 转换为“Firm”数组,即数组中所有元素的最大公约数(GCD)大于 1。可以通过增加或减少数组中的任意元素来实现这一目标,并且需要计算出最少的操作次数。
数据结构选择
- 素数列表:我们选择了一个素数列表
primes,用于存储小于等于某个上限的素数。这个列表将用于后续的计算。 - 布尔数组:在
findPrimes函数中,使用了一个布尔数组is_prime来标记每个数是否为素数。
算法步骤
-
生成素数列表:
- 使用埃拉托斯特尼筛法(Sieve of Eratosthenes)来生成小于等于
1000的素数列表。
- 使用埃拉托斯特尼筛法(Sieve of Eratosthenes)来生成小于等于
-
计算最小操作次数:
- 对于每个素数
p,计算将数组A中的每个元素调整为p的倍数所需的最小操作次数。 - 具体来说,对于数组中的每个元素
i,计算i % p和p - i % p的较小值,并将这些值累加起来,得到将整个数组调整为p的倍数所需的操作次数。 - 遍历所有素数,并记录最小的操作次数。
- 对于每个素数
具体实现
// 生成素数列表
vector<int> primes;
void findPrimes(int n) {
if (n <= 1) return;
vector<bool> is_prime(n, true);
is_prime[0] = is_prime[1] = false; // 0 and 1 are not prime numbers
for (int i = 2; i <= sqrt(n); ++i) {
if (is_prime[i]) {
for (int j = i * i; j < n; j += i) {
is_prime[j] = false;
}
}
}
for (int i = 2; i <= n; ++i) {
if (is_prime[i]) {
primes.push_back(i);
}
}
}
// 计算最小操作次数
int solution(int N, const std::vector<int>& A) {
// write code here
int ret = INT_MAX;
findPrimes(1000);
for(int p : primes){
int cur=0;
for(int i : A){
cur += min(i % p, p - i % p);
}
ret = min(ret, cur);
}
return ret;
}
《小C的数字倍数问题》题面如下:
问题理解
我们需要计算在区间 [l, r] 内,有多少个数是 a 的倍数,或者是 b 的倍数,或者是 c 的倍数。
解题思路
-
基本思路:
- 计算区间
[l, r]内a的倍数的个数。 - 计算区间
[l, r]内b的倍数的个数。 - 计算区间
[l, r]内c的倍数的个数。 - 由于
a、b、c的倍数可能有重叠,我们需要使用容斥原理来避免重复计数。
- 计算区间
-
容斥原理:
- 计算
a和b的倍数的重叠部分。 - 计算
a和c的倍数的重叠部分。 - 计算
b和c的倍数的重叠部分。 - 计算
a、b、c的倍数的重叠部分。
- 计算
-
具体步骤:
- 计算每个数的倍数个数:
count(x) = r/x - (l-1)/x。 - 使用容斥原理计算总的倍数个数。
- 计算每个数的倍数个数:
代码实现思路
-
计算最小公倍数:
- 使用
lcm函数计算两个数的最小公倍数。
- 使用
-
处理重复倍数:
- 通过排序和去除重复的倍数因子,简化后续的容斥原理计算。
-
容斥原理应用:
- 根据
base数组的大小,分别处理不同数量的因子组合。
- 根据
具体实现
int lcm(int a, int b){
return a * b / __gcd(a, b);
}
int solution(int a, int b, int c, int l, int r) {
// write code here
int ret=0;
vector<int> base = {a,b,c};
sort(base.begin(), base.end());
if(base[2] % base[0] == 0 || base[2] % base[1] == 0){
base.pop_back();
if(base[1] % base[0] == 0){
base.pop_back();
}
} else {
if(base[1] % base[0] == 0){
base[1] = base[2];
base.pop_back();
}
}
for(int i : base){
ret += r/i - (l-1)/i;
}
if(base.size() == 3){
a = base[0], b = base[1], c = base[2];
ret -= r/lcm(a,b) - (l-1)/lcm(a,b) + r/lcm(a,c) - (l-1)/lcm(a,c) + r/lcm(b,c) - (l-1)/lcm(b,c);
} else if(base.size() == 2){
a = base[0], b = base[1];
ret -= r/lcm(a,b) - (l-1)/lcm(a,b);
}
return ret;
}
借助豆包MarsCode AI刷题平台,我们不仅高效地解决了《最小操作数使数组变为 Firm 数组》和《小C的数字倍数问题》,还加深了对相关算法和数据结构的理解,后续会借助豆包MarsCode AI给大家展示更多题目的解法。