查找数组中的一对元素的最小GCD

问题描述 投票:0回答:1

给定一个元素数组,我必须找到MINIMUM GCD在阵列的任何两对之间,以最小的时间复杂度。

示例

输入

arr=[7,3,14,9,6]

约束

N= 10^ 5

输出

1

说明

min gcd can be of pair(7,3)

我的幼稚解决方案-O(n ^ 2)幼稚的蛮力

int ans=INT_MAX;

for (int i = 0; i < n; ++i)
{
    for(int j=i+1; j<n; j++){
        int g= __gcd(arr[i],arr[j]);
        ans=min(ans,g);
    }
}

return ans;

您能建议一种最小化时间复杂度的更好方法吗?

primes prime-factoring number-theory greatest-common-divisor modular-arithmetic
1个回答
0
投票

此解决方案在时间O(n + h log h)内起作用,其中h是数组中的最大值。让我们解决一个更棘手的问题:对于每个x <= h,计算无序对(i,j)的数目d [x],使得0 <= i,j

Mobius求逆可用于解决以下问题:您需要找到一个数组y,但是却给了一个数组z,使得z [k] = y [k] + y [2 * k] + y [ 3 * k] + ....令人惊讶的是,它可以就地运行,而且只有三行代码!

这正是我们所需要的,首先我们要找到有序对(i,j)的数量,使得d [x] divides GCD(a [i],a [j]),但是我们需要有序对(i,j)的数量,以使d [x] is GCD(a [i],a [j])。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

typedef long long ll;

int main() {
    int n, h = 0;
    cin >> n;
    vector<int> a(n);
    for (int& x : a) {
        cin >> x;
        h = max(h, x);
    }
    h++;
    vector<ll> c(h), d(h);
    for (int x : a)
        c[x]++;

    for (int i=1; i<h; i++)
        for (int j=i; j<h; j+=i)
            d[i] += c[j];

    // now, d[x] = no. of indices i such that x divides a[i] 

    for (int i=1; i<h; i++)
        d[i] *= d[i];

    // now, d[x] = number of pairs of indices (i, j) such that
    // x divides a[i] and a[j] (just square the previous d)
    // equiv. x divides GCD(a[i], a[j])

    // apply Mobius inversion to get proper values of d
    for (int i=h-1; i>0; i--)
        for (int j=2*i; j<h; j+=i)
            d[i] -= d[j];

    for (int i=1; i<h; i++) {
        if (d[i]) {
            cout << i << '\n';
            return 0;
        }
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.