📌  相关文章
📜  具有单位 GCD 的子序列的最小长度(1)

📅  最后修改于: 2023-12-03 14:50:06.985000             🧑  作者: Mango

具有单位 GCD 的子序列的最小长度

在数学中,最大公约数(Greatest Common Divisor,简称 GCD)指的是几个整数的公共约数中最大的一个。如果两个整数的最大公约数为 1,则这两个整数互质,可以简写为 $GCD(a,b)=1$。在一个序列中,如果任意两个数的 GCD 都为 1,则该序列被称为具有单位 GCD。

现在我们来考虑一个问题:对于一个长度为 $n$ 的序列 $a_1,a_2,...,a_n$,我们想要找到一个长度最短的非空子序列,使得该子序列具有单位 GCD。那么,如何求解这个问题呢?

解法

实际上,该问题有一个非常直观的暴力解法:枚举所有的非空子序列,对每个子序列计算其 GCD 是否为 1。如果该子序列的 GCD 为 1,则更新最小长度。这种做法的时间复杂度为 $O(n^3)$,显然无法满足实际的需求。

但是,我们可以使用一些技巧将时间复杂度优化至 $O(n \log^2 n)$。具体来说,我们考虑使用线性筛法快速计算出所有的质数,然后对于每个质数,我们找到所有能够被该质数整除的数,组成一个子序列。如果该子序列的长度大于该质数,则一定存在一个长度为该质数的非空子序列,该子序列的 GCD 为该质数。因此,我们可以直接更新最小长度。这种做法的正确性可以通过反证法得到证明。

具体实现细节可以参考下面的代码实现。

const int MAXN = 1e5 + 5;
int n, a[MAXN], vis[MAXN], prime[MAXN], tot;
int mn[MAXN], ans = INT_MAX;

void init() {
    mn[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!vis[i]) {
            prime[++tot] = i;
            mn[i] = 1;
        }
        for (int j = 1; j <= tot && i * prime[j] <= n; ++j) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                mn[i * prime[j]] = mn[i];
                break;
            }
            mn[i * prime[j]] = std::min(mn[i], prime[j]);
        }
    }
}

void solve() {
    std::map<int, int> mp; mp.clear();
    for (int i = 1; i <= n; ++i) {
        if (a[i] == 1) {
            ans = 1;
            return;
        }
        int x = a[i] / mn[a[i]];
        int tmp = mp[x];
        if (tmp) {
            ans = std::min(ans, i - tmp + 1);
        }
        mp[x] = tmp ? tmp : i;
    }
}

int main() {
    std::cin >> n;
    for (int i = 1; i <= n; ++i) {
        std::cin >> a[i];
    }
    init();
    solve();
    std::cout << ans << std::endl;
    return 0;
}

上面的代码中,mn[i] 表示整数 $i$ 的最小质因子。我们可以使用线性筛法求出所有的最小质因子,并预处理出 $mn$ 数组。然后对于每个质数 $p$,我们可以找到所有能够被 $p$ 整除的数,组成一个子序列,并使用 std::map 维护子序列中的最早出现位置。最后遍历原序列,对于每个数,我们找到其对应的质因子 $p$,计算 $a_i / \text{mn}[a_i]$ 的值,并在 std::map 中查找是否存在相同值。若存在,则说明该子序列的长度不小于 $p$,并更新最小长度即可。

总结

这个问题需要我们从数学和算法两个角度来考虑。虽然暴力解法不难想到,但是时间复杂度极高,无法通过本题。线性筛法则是一种非常常用的算法,可以快速计算所有的质数以及所有数的最小质因子。通过巧妙地利用线性筛法,我们可以将时间复杂度优化至 $O(n \log^2 n)$,达到了较好的效果。