📌  相关文章
📜  从数组中删除的最小数量以使 GCD 更大

📅  最后修改于: 2021-10-27 07:40:54             🧑  作者: Mango

给定 N 个数字,任务是找到最小的移除数字,使得剩余数字的 GCD 大于 N 个数字的初始 GCD。如果不能增加 GCD,打印“NO”。

例子:

按照以下步骤解决上述问题:

  1. 最初使用欧几里德算法找到 N 个数字的 gcd。
  2. 将所有数字除以得到的 gcd。
  3. 使用多查询的质因数分解方法,在 O(log N) 中找到每个数字的质数因数分解。该方法可以在这里阅读。
  4. 插入集合中的所有质因子以删除使用此方法获得的重复项。
  5. 使用哈希映射,计算每个第 i 个元素中素因子的频率。
  6. 一旦数字的因式分解完成,并且计数已存储在频率表中,则在哈希图中迭代并找出出现次数最多的素因数。它不能是 N,因为我们已经将数组元素最初除以 N 个数字的初始 gcd。
  7. 如果在初始 gcd 划分后存在任何此类因素,则移除次数将始终为 n-(hash[prime_factor])。

下面是上述方法的实现。

C++
// C++ program to find the minimum removals
// such that gcd of remaining numbers is more
// than the initial gcd of N numbers
#include 
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 getFactorization(int x)
{
    vector 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 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 p = getFactorization(a[i]);
        set 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;
}


Java
// Java program to find the minimum removals
// such that gcd of remaining numbers is more
// than the initial gcd of N numbers
import java.util.*;
 
class GFG{
 
static final int MAXN = 100001;
 
// stores smallest prime factor for every number
static int []spf = new int[MAXN];
 
// Calculating SPF (Smallest Prime Factor)
// for every number till MAXN.
// Time Complexity : O(nloglogn)
static 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
static Vector getFactorization(int x)
{
    Vector ret = new Vector<>();
    while (x != 1)
    {
        ret.add(spf[x]);
        x = x / spf[x];
    }
    return ret;
}
 
// Recursive function to return gcd of a and b 
static int __gcd(int a, int b) 
{ 
    return b == 0 ? a : __gcd(b, a % b);    
}
 
// Function which returns the minimal
// removals required to make gcd
// greater than previous
static int minimumRemovals(int a[], int n)
{
    int g = 0;
 
    // Finding initial gcd
    for(int i = 0; i < n; i++)
        g = __gcd(a[i], g);
 
    HashMap mpp = new HashMap<>();
 
    // 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++)
    {
         
        // Prime factorisation to get the prime
        // factors of i-th element in the array
        Vector p = getFactorization(a[i]);
        HashSet s = new HashSet<>();
 
        // Insert all the prime factors in
        // set to remove duplicates
        for(int j = 0; j < p.size(); j++)
        {
            s.add(p.get(j));
        }
 
        // Increase the count of prime
        // factor in map for every element
        for(int it: s)
        {
            int el = it;
            if (mpp.containsKey(el))
            {
                mpp.put(el, mpp.get(el) + 1);
            }
            else
            {
                mpp.put(el, 1);
            }
        }
    }
 
    int mini = Integer.MAX_VALUE;
    int mini1 = Integer.MAX_VALUE;
 
    // Iterate in map and check for
    // every factor and its count
    for(Map.Entry it : mpp.entrySet())
    {
        int fir = it.getKey();
        int sec = it.getValue();
 
        // Check for the largest appearing factor
        // which does not appears in any one or more
        if ((n - sec) <= mini)
        {
            mini = n - sec;
        }
    }
    if (mini != Integer.MAX_VALUE)
        return mini;
    else
        return -1;
}
 
// Driver code
public static void main(String[] args)
{
    int a[] = { 6, 9, 15, 30 };
    int n = a.length;
     
    sieve();
     
    System.out.print(minimumRemovals(a, n));
}
}
 
// This code is contributed by Amit Katiyar


Python3
# Python3 program to find the minimum removals
# such that gcd of remaining numbers is more
# than the initial gcd of N numbers
from math import gcd as __gcd
 
MAXN = 100001
 
# stores smallest prime factor for every number
spf = [i for i in range(MAXN)]
 
# Calculating SPF (Smallest Prime Factor) for every
# number till MAXN.
# Time Complexity : O(nloglogn)
def sieve():
 
    # separately marking spf for every even
    # number as 2
    for i in range(4, MAXN, 2):
        spf[i] = 2
 
    for i in range(3, MAXN):
 
        if i * i > MAXN:
            break
 
        # checking if i is prime
        if (spf[i] == i):
 
            # marking SPF for all numbers divisible by i
            for j in range(2 * i, MAXN, 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
def getFactorization(x):
    ret = []
    while (x != 1):
        ret.append(spf[x])
        x = x // spf[x]
    return ret
 
# Function which returns the minimal
# removals required to make gcd
# greater than previous
def minimumRemovals(a, n):
    g = 0
 
    # finding initial gcd
    for i in range(n):
        g = __gcd(a[i], g)
 
    mpp = dict()
 
    # divides all number by initial gcd
    for i in range(n):
        a[i] = a[i] // g
 
    # iterating for all numbers
    for i in range(n):
 
        # primt factorisation to get the prime
        # factors of i-th element in the array
        p = getFactorization(a[i])
        s = dict()
 
        # insert all the prime factors in
        # set to remove duplicates
        for j in range(len(p)):
            s[p[j]] = 1
 
        # increase the count of prime
        # factor in map for every element
        for i in s:
            mpp[i] = mpp.get(i, 0) + 1
 
    mini = 10**9
    mini1 = 10**9
 
    # iterate in map and check for every factor
    # and its count
    for i in mpp:
        fir = i
        sec = mpp[i]
 
        # check for the largest appearing factor
        # which does not appears in any one or more
        if ((n - sec) <= mini):
            mini = n - sec
 
    if (mini != 10**9):
        return mini
    else:
        return -1
 
# Driver code
a = [6, 9, 15, 30]
n = len(a)
sieve()
print(minimumRemovals(a, n))
 
# This code is contributed by mohit kumar 29


C#
// C# program to find the minimum
// removals such that gcd of remaining
// numbers is more than the initial
// gcd of N numbers
using System;
using System.Collections.Generic;
class GFG{
 
static readonly int MAXN = 100001;
 
// stores smallest prime
// factor for every number
static int []spf =
       new int[MAXN];
 
// Calculating SPF (Smallest
// Prime Factor) for every
// number till MAXN.
// Time Complexity : O(nloglogn)
static 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
static List getFactorization(int x)
{
  List ret = new List();
   
  while (x != 1)
  {
    ret.Add(spf[x]);
    x = x / spf[x];
  }
  return ret;
}
 
// Recursive function to
// return gcd of a and b 
static int __gcd(int a,
                 int b) 
{ 
  return b == 0 ? a :
         __gcd(b, a % b);    
}
 
// Function which returns the
// minimal removals required
// to make gcd greater than
// previous
static int minimumRemovals(int []a,
                           int n)
{
  int g = 0;
 
  // Finding initial gcd
  for(int i = 0; i < n; i++)
    g = __gcd(a[i], g);
 
  Dictionary mpp = new Dictionary();
 
  // 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++)
  {
    // Prime factorisation to get the prime
    // factors of i-th element in the array
    List p = getFactorization(a[i]);
    HashSet s = new HashSet();
 
    // Insert all the prime factors in
    // set to remove duplicates
    for(int j = 0; j < p.Count; j++)
    {
      s.Add(p[j]);
    }
 
    // Increase the count of prime
    // factor in map for every
    // element
    foreach(int it in s)
    {
      int el = it;
      if (mpp.ContainsKey(el))
      {
        mpp[el]= mpp[el] + 1;
      }
      else
      {
        mpp.Add(el, 1);
      }
    }
  }
 
  int mini = int.MaxValue;
  int mini1 = int.MaxValue;
 
  // Iterate in map and check for
  // every factor and its count
  foreach(KeyValuePair it in mpp)
  {
    int fir = it.Key;
    int sec = it.Value;
 
    // 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.MaxValue)
    return mini;
  else
    return -1;
}
 
// Driver code
public static void Main(String[] args)
{
  int []a = {6, 9, 15, 30};
  int n = a.Length;
  sieve();
  Console.Write(minimumRemovals(a, n));
}
}
 
// This code is contributed by Rajput-Ji


Javascript


输出:
2

时间复杂度: O(log log N) 用于预计算 Sieve,O(N * log N) 用于计算。
辅助空间: O(N)