可以将数组划分为的最大子数组,使得不同子数组中任意两个元素的GCD始终为1?

时间:2017-03-29 11:21:51

标签: c++ arrays algorithm

给定n,数组元素的数量和arr[n](数字数组),需要找到数组可以分成的最大子数组,以便{{1对于属于不同子阵列的每个GCD(a,b)=1a

例如:

b

每一次进一步分裂的尝试都不符合条件。

我的方法:
1.对阵列进行排序 2.继续计算元素的5 2 3 4 5 6 Ans: 2 ----> {(2,3,4,6),(5)} 3.每次元素的lcm和之前元素的gcdlcm时,都会增加计数器。

1

在多次判断int main() { int n; cin>>n; long long int arr[n]; for(int i=0;i<n;++i) cin>>arr[i]; sort(arr,arr+n); long long int ans=1,l=arr[n-1]; for(int i=n-2;i>=0;i--) { if(gcd(l,arr[i])==1) ans++; l=lcm(l,arr[i]); } cout<<ans<<endl; return 0; } 的答案后,我很困惑我的解决方案是否正确。由于wrong answer的限制为n且数组元素为10^6,因此解决方案失败的另一个原因是10^7可能超出LCM限制。还有其他解决方案吗?或者目前的方法有什么错误吗?

1 个答案:

答案 0 :(得分:1)

我认为这是您所指的问题:https://www.codechef.com/problems/CHEFGRUP

我的方法如下(我超时限制)

步骤1:计算[1,10 ^ 7]范围内的所有素数。

这可以使用Sieve of Eratosthenes完成,复杂性为O(nlog(log(n)),其中n可以高达10^7

步骤-2:使用上面计算的素数向量来查找数组中所有数字的素数因子分解。

一旦我们拥有所有必需的素数,这可以非常有效地实现。

在这一步中要注意的一点是,假设我们有2个数字,其素数因子分解包含公共素数,那么这两个元素不能在不同的子阵列中,因为GCD不会是1(根据要求题)。因此,对于所有这样的对,它们必须处于相同的子阵列中。怎么做到这一点?

步骤-3:使用不相交集数据结构。

我们可以创建一个不相交的所有素数集。因此,开头的集合数量将是素数的数量。然后,在每个分解期间,我们将加入作为除数的所有素数,并将它们全部添加到具有原始数字的同一组中。这将对所有数字重复。

此外,我们必须检查一次,是否首先需要一些素数。因为在此步骤之前我们假设存在与范围中的素数一样多的集合。但有些可能未被使用。因此,可以通过遍历一次循环并查找唯一代表的数量来检查。这将是我们的答案。

我的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;

int prime[(int)1e7+10] = {0};

struct union_find {
    std::vector <int> parent, rank;

    // Constructor to initialse 'parent' and 'rank' vector.
    union_find(int n) {
        parent = std::vector <int> (n);
        rank = std::vector <int> (n, 0);        // initialse rank vector with 0.
        for(int i = 0; i < n; i++)
            parent[i] = i;
    }

    // Find with Path Compression Heuristic.
    int find_(int a) {
        if(a == parent[a])
            return a;
        return parent[a] = find_(parent[a]);
    }

    // Union by checking rank to keep the depth of the tree as shallow as possible.
    void union_(int a, int b) {
        int aa = find_(a), bb = find_(b);
        if(rank[aa] < rank[bb])
            parent[aa] = bb;
        else
            parent[bb] = aa;
        if(rank[aa] == rank[bb])
            ++rank[aa];
    }
};

union_find ds(1e7+10);

int main() {
    int n;
    int sq = sqrt(1e7+10);
    for(int i = 4; i < 1e7+10; i += 2)
        prime[i] = 1;
    for(int i = 3; i <= sq; i += 2) {
        if(!prime[i]) {
            for(int j = i*i; j < 1e7+10; j += i)
                prime[j] = 1;
        }
    }

    vector <int> primes;
    primes.push_back(2);
    for(int i = 3; i < 1e7+10; i += 2) {
        if(!prime[i])
            primes.push_back(i);
    }


    scanf("%d", &n);
    int a[n];
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }

    for(int i = 0; i < n; i++) {

        int temp = a[i];
        // int sq = sqrt(temp);
        vector <int> divisors;
        for(int j = 0; j < primes.size(); j++) {
            if(primes[j] > temp)
                break;
            if(temp % primes[j] == 0) {
                divisors.push_back(primes[j]);
                while(temp % primes[j] == 0) {
                    temp /= primes[j];
                }
            }
        }
        if(temp > 2)
            divisors.push_back(temp);

        for(int i = 1; i < divisors.size(); i++)
            ds.union_(divisors[i], divisors[i-1]);
        if(divisors.size() > 0)
            ds.union_(divisors[0], a[i]);
    }

    set <int> unique;
    for(int i = 0; i < n; i++) {
        int x = ds.find_(a[i]);
        unique.insert(x);
    }

    printf("%d\n", unique.size());
    return 0;
}