Minimum removals from array to make GCD greater

Given N numbers, the task is to find the minimum removal of numbers such that GCD of the remaining numbers is greater than initial GCD of N numbers. If it is not possible to increase the GCD, print “NO”.

Examples:

Input: a[] = {1, 2, 4}
Output: 1
Remove the first element, then the new GCD is 2, which is greater than the initial GCD i.e., 1.

Input: a[] = {6, 9, 15, 30}
Output: 2
The initial gcd is 3, remove 6 and 9 to obtain a gcd of 15 which is greater than 3. You can also remove 9 and 15 to get a gcd of 6.



The following steps are followed to solve the above problem:

  1. Initially find the gcd of N numbers using Euclidean algorithms.
  2. Divide all numbers by the obtained gcd.
  3. Using prime factorization for multiple queries method, find the prime factorization of every number in O(log N). The method can be read here.
  4. Insert all the prime factors in the set to remove duplicates which are obtained using this method.
  5. Using a hash-map, count the frequencies of the prime factors in every i-th element.
  6. Once the factorization of numbers have been done, and the count has been stored in the frequency table, iterate in the hash-map and find out the prime factor which occurs the maximum number of times. It cannot be N, as we have already divided the array elements initially by the initial gcd of N numbers.
  7. The number of removals will always be n-(hash[prime_factor]) if there are any such factors after divison of initial gcd.

Below is the implementation of the above approach.

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find the minimum removals
// such that gcd of remaining numbers is more
// than the initial gcd of N numbers
#include <bits/stdc++.h>
using namespace std;
  
#define MAXN 100001
  
// stores smallest prime factor for every number
int spf[MAXN];
  
// Calculating SPF (Smallest Prime Factor) for every
// number till MAXN.
// Time Complexity : O(nloglogn)
void sieve()
{
    spf[1] = 1;
    for (int i = 2; i < MAXN; i++)
  
        // marking smallest prime factor for every
        // number to be itself.
        spf[i] = i;
  
    // separately marking spf for every even
    // number as 2
    for (int i = 4; i < MAXN; i += 2)
        spf[i] = 2;
  
    for (int i = 3; i * i < MAXN; i++) {
  
        // checking if i is prime
        if (spf[i] == i) {
  
            // marking SPF for all numbers divisible by i
            for (int j = i * i; j < MAXN; j += i)
  
                // marking spf[j] if it is not
                // previously marked
                if (spf[j] == j)
                    spf[j] = i;
        }
    }
}
  
// A O(log n) function returning primefactorization
// by dividing by smallest prime factor at every step
vector<int> getFactorization(int x)
{
    vector<int> ret;
    while (x != 1) {
        ret.push_back(spf[x]);
        x = x / spf[x];
    }
    return ret;
}
  
// Function which returns the minimal
// removals required to make gcd
// greater than previous
int minimumRemovals(int a[], int n)
{
    int g = 0;
  
    // finding initial gcd
    for (int i = 0; i < n; i++)
        g = __gcd(a[i], g);
  
    unordered_map<int, int> mpp;
  
    // divides all number by initial gcd
    for (int i = 0; i < n; i++)
        a[i] = a[i] / g;
  
    // iterating for all numbers
    for (int i = 0; i < n; i++) {
  
        // primt factorisation to get the prime
        // factors of i-th element in the array
        vector<int> p = getFactorization(a[i]);
        set<int> s;
  
        // insert all the prime factors in
        // set to remove duplicates
        for (int j = 0; j < p.size(); j++) {
            s.insert(p[j]);
        }
  
        /// increase the count of prime
        // factor in map for every element
        for (auto it = s.begin(); it != s.end(); it++) {
            int el = *it;
            mpp[el] += 1;
        }
    }
  
    int mini = INT_MAX;
    int mini1 = INT_MAX;
  
    // iterate in map and check for every factor
    // and its count
    for (auto it = mpp.begin(); it != mpp.end(); it++) {
        int fir = it->first;
        int sec = it->second;
  
        // check for the largest appearing factor
        // which does not appears in any one or more
        if ((n - sec) <= mini) {
            mini = n - sec;
        }
    }
    if (mini != INT_MAX)
        return mini;
    else
        return -1;
}
  
// Driver code
int main()
{
    int a[] = { 6, 9, 15, 30 };
    int n = sizeof(a) / sizeof(a[0]);
    sieve();
    cout << minimumRemovals(a, n);
    return 0;
}

chevron_right


Output:

2


Time Complexity:
O(log log N) for precalculation of Seive, and O(N * log N) for calculation.
Auxiliary Space: O(N)



My Personal Notes arrow_drop_up

Striver(underscore)79 at Codechef and codeforces D

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.