当前位置: 首页 > 知识库问答 >
问题:

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

史宸
2023-03-14

给定< code>n,数组元素的数目和< code>arr[n],数字数组,需要找到数组可以分成的子数组的最大数目,使得对于属于不同子数组的每个< code>a和< code>b,< code>GCD(a,b)=1。

例如:

5
2 3 4 5 6
Ans: 2 ----> {(2,3,4,6),(5)}

任何其他进一步分裂它的企图都不会满足这些条件。

我的方法:
1.对数组进行排序
2.继续计算元素的lcm
3.每当元素的gcd和之前元素的lcm1时,增加计数器。

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;
} 

在我的答案被多次判断为错误答案之后,我很困惑我的答案是否正确。由于n的限制为10^6,数组元素为10^7,因此解决方案失败的另一个原因是


共有1个答案

慕皓君
2023-03-14

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

我的方法如下(我超过了时间限制):

这可以使用埃拉托色尼筛来完成,复杂度将是O(nlog(log(n))其中n最多可以是10^7

一旦我们有了所有需要的质数,这就可以非常有效地实现。

在这一步中需要注意的一点是,假设我们有两个数,其素数分解包含公共素数,那么这两个元素不能在不同的子数组中,因为GCD不会是1(如问题中所要求的)。因此,对于所有这些对,它们必须位于同一子阵列中。如何实现这一点?

我们可以创建一个所有素数的不相交集。所以开始时的集合数将是素数的数量。然后,在每次因式分解期间,我们将连接所有作为除数的素数,并将它们与原始数相加在同一个组中。这将对所有数字重复。

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

我的代码:

#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;
}
 类似资料:
  • 有没有一种方法可以在小于O(n^2)的时间内做到这一点。 O(nlogn)还是O(n)?

  • 我有一个由32个数字组成的数组[1,2,3,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,7,7,7,7,8,9,10,10,11,9,12,13,13,14,14,15,16,17,17] 对于我最初的问题,我不需要生成所有的排列。我只需要在每次运行我的程序时生成一个随机排列。 我的方法是使用Fisher-Yates算法随机洗牌数组,并不断重新洗牌,直到我得到所有8个子数组,没有重

  • O(n^2)算法简单。有没有人对此有更好的算法?

  • 问题内容: 我有很多对象,我需要将它们分成两个组成一组,以供UI助手使用。 例: 通过这四个数组成为一个数组 有很多分割数组的方法。但是,如果阵列很大,什么是最有效的(成本最低)。 问题答案: 如果您正在寻找效率,则可以使用一种方法来懒散地生成每个包含2个元素的数组,因此您一次只能在内存中存储2个元素: 此方法适用于任何Array,而不仅限于Arrays。 对于Swift 1,没有协议扩展,您将拥

  • 给定一个数字数组,查找是否有方法从数组中删除/移除一个数字,并在数组中进行一个分区(将数组划分为两个子数组),以使子数组1中的元素和等于子数组2中的元素和。 现在让我们考虑一个例子:- 现在一个类似的问题已经存在,我们只需要,找到是否数组可以被分成两个子数组相等的和,可以在O(n) =中完成 伪代码:-有效的解决方案包括提前计算阵列中所有元素的总和。然后,对于数组中的每个元素,我们可以通过使用数组