📅  最后修改于: 2023-12-03 15:10:22.756000             🧑  作者: Mango
给定一个长度为 $n$ 的数组 $a$,如果 $i \geq 2$,则 $a_i$ 可以写成 $a_{i-1} + \gcd(a_{i-1}, a_{i-2})$ 的形式。求字典序最大的 $a$ 数组。
首先考虑到 $a_i$ 是由前两个数 $a_{i-1}$ 和 $a_{i-2}$ 来得到的,而且 $\gcd$ 表示的是最大公约数,所以很容易想到贪心算法。
我们可以从小到大枚举 $a$ 数组中的值,对于每一个 $a_i$ ,将 $a_{i-1}$ 的值枚举从大到小,找到满足 $a_i = a_{i-1} + \gcd(a_{i-1}, a_{i-2})$ 的最大值 $a_{i-1}$ ,然后将 $a_{i-2}$ 更新为 $a_{i-1}$,继续往后推。
在更新 $a_i$ 的过程中,我们可以用一个桶来存储每个数出现的次数,这样就可以方便地找到下一个最大的 $a_{i-1}$。
这里给出 C++ 代码实现。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int MAXN = 100005;
int n;
int a[MAXN], t[MAXN];
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
int main() {
scanf("%d", &n);
memset(t, 0, sizeof(t));
for (int i = 1; i <= n; i++) {
for (int j = i == 1 ? 1 : a[i-1] + 1; j <= 2e5; j++) {
int g = i == 2 ? 0 : gcd(a[i-1], a[i-2]);
if (j == g + a[i-1] && t[j] == 0) {
a[i] = j;
t[j] = 1;
break;
}
}
}
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
return 0;
}
此外,为了避免重复计算,我们可以将计算过的值存储到一个桶中,以便下次查询时直接查找,而不是再进行计算。