📜  计算GCD等于给定数的集合的子集数

📅  最后修改于: 2021-05-07 06:59:12             🧑  作者: Mango

给定一组正整数元素,找到GCD等于给定数字的子集的数量。
例子:

Input:  arr[] = {2, 3, 4}, gcd[] = {2, 3}
Output: Number of subsets with gcd 2 is 2
        Number of subsets with gcd 3 is 1
The two subsets with GCD equal to 2 are {2} and {2, 4}.
The one subset with GCD equal to 3 ss {3}.

Input:  arr[] = {6, 3, 9, 2}, gcd = {3, 2}
Output: Number of subsets with gcd 3 is 5
        Number of subsets with gcd 2 is 2
The five subsets with GCD equal to 3 are {3}, {6, 3}, 
{3, 9}, {6, 9) and {6, 3, 9}.  
The two subsets with GCD equal to 2 are {2} and {2, 6}                

强烈建议您最小化浏览器,然后自己尝试。
一个简单的解决方案是生成给定集合的所有子集,并找到每个子集的GCD。
以下是针对小数字的有效解决方案,即所有数字的最大值不是很高。

1) Find the maximum number of given numbers.  Let the 
   maximum be arrMax.
2) Count occurrences of all numbers using a hash. Let 
   this hash be 'freq'
3) The maximum possible GCD can be arrMax. Run a loop 
   for i = arrMax to 1
     a) Count number of subsets for current GCD. 
4) Now we have counts for all possible GCDs, return
   count for given gcds. 

步骤3.a如何工作?
如何获取给定GCD’i’的子集数量,其中i处于1到arrMax范围内。想法是使用内置的“ freq”步骤2计算i的所有倍数。让i的“ add”倍数存在。所有带有“ add”数字的可能子集的数量将为“ pow(2,add)– 1”,不包括空集。例如,如果给定数组为{2,3,6}且i = 3,则存在3的2的倍数(3和6)。因此,将存在3个子集{3},{3、6}和{6},它们的i倍数是GCD。这些子集还包括{6},它没有3作为GCD,而是3的倍数。因此,我们需要减去这些子集。我们将每个GCD的子集计数存储在另一个哈希图“子集”中。令’sub’为GCD中具有’i’的倍数的子集的数量。当我们正在评估从arrMax到1的计数时,可以直接从subset []获得’i’任意倍数的’sub’值。
以下是上述想法的实现。

C++
// C++ program to count number of subsets with given GCDs
#include
using namespace std;
 
// n is size of arr[] and m is sizeof gcd[]
void ccountSubsets(int arr[], int n, int gcd[], int m)
{
    // Map to store frequency of array elements
    unordered_map freq;
 
    // Map to store number of subsets with given gcd
    unordered_map subsets;
 
    // Initialize maximum element. Assumption: all array
    // elements are positive.
    int arrMax = 0;
 
    // Find maximum element in array and fill frequency
    // map.
    for (int i=0; i=1; i--)
    {
        int sub = 0;
        int add = freq[i];
 
        // Run a loop for all multiples of i
        for (int j = 2; j*i <= arrMax; j++)
        {
            // Sum the frequencies of every element which
            // is a multiple of i
            add += freq[j*i];
 
            // Excluding those subsets which have gcd > i but
            // not i i.e. which have gcd as multiple of i in
            // the subset for ex: {2,3,4} cnsidering i = 2 and
            // subset we need to exclude are those havng gcd as 4
            sub += subsets[j*i];
        }
         
        // Number of subsets with GCD equal to 'i' is pow(2, add)
        // - 1 - sub   
        subsets[i] = (1<


Java
// Java program to count
// number of subsets with
// given GCDs
import java.util.*;
class GFG{
 
// n is size of arr[] and
// m is sizeof gcd[]
static void ccountSubsets(int arr[], int n,
                          int gcd[], int m)
{
  // Map to store frequency
  // of array elements
  HashMap freq =
          new HashMap();
 
  // Map to store number of
  // subsets with given gcd
  HashMap subsets =
          new HashMap();
 
  // Initialize maximum element.
  // Assumption: all array
  // elements are positive.
  int arrMax = 0;
 
  // Find maximum element in
  // array and fill frequency
  // map.
  for (int i = 0; i < n; i++)
  {
    arrMax = Math.max(arrMax,
                      arr[i]);
    if(freq.containsKey(arr[i]))
    {
      freq.put(arr[i],
      freq.get(arr[i]) + 1);
    }
    else
    {
      freq.put(arr[i], 1);
    }
  }
 
  // Run a loop from max element
  // to 1 to find subsets
  // with all gcds
  for (int i = arrMax; i >= 1; i--)
  {
    int sub = 0;
    int add = 0;
    if(freq.containsKey(i))
      add = freq.get(i);
 
    // Run a loop for all multiples
    // of i
    for (int j = 2; j * i <= arrMax; j++)
    {
      // Sum the frequencies of
      // every element which
      // is a multiple of i
      if(freq.containsKey(i * j))
        add += freq.get(j * i);
 
      // Excluding those subsets
      // which have gcd > i but
      // not i i.e. which have
      // gcd as multiple of i in
      // the subset for ex: {2,3,4}
      // cnsidering i = 2 and
      // subset we need to exclude
      // are those havng gcd as 4
      sub += subsets.get(j * i);
    }
 
    // Number of subsets with GCD
    // equal to 'i' is Math.pow(2, add)
    // - 1 - sub  
    subsets.put(i, (1 << add) -
                1 - sub);
  }
 
  for (int i = 0; i < m; i++)
    System.out.print("Number of subsets with gcd " + 
                     gcd[i] + " is " +
                     subsets.get(gcd[i]) + "\n");
}
 
// Driver program
public static void main(String[] args)
{
  int gcd[] = {2, 3};
  int arr[] = {9, 6, 2};
  int n = arr.length;
  int m = gcd.length;
  ccountSubsets(arr, n, gcd, m);
}
}
 
// This code is contributed by shikhasingrajput


Python3
# Python3 program to count number of
# subsets with given GCDs
 
# n is size of arr[] and m is sizeof gcd[]
def countSubsets(arr, n, gcd, m):
 
    # Map to store frequency of array elements
    freq = dict()
 
    # Map to store number of subsets
    # with given gcd
    subsets = dict()
 
    # Initialize maximum element.
    # Assumption: all array elements
    # are positive.
    arrMax = 0
 
    # Find maximum element in array and
    # fill frequency map.
    for i in range(n):
        arrMax = max(arrMax, arr[i])
        if arr[i] not in freq:
            freq[arr[i]] = 1
        else:
            freq[arr[i]] += 1
 
    # Run a loop from max element to 1
    # to find subsets with all gcds
    for i in range(arrMax, 0, -1):
        sub = 0
        add = 0
        if i in freq:
            add = freq[i]
        j = 2
 
        # Run a loop for all multiples of i
        while j * i <= arrMax:
 
            # Sum the frequencies of every element
            # which is a multiple of i
            if j * i in freq:
                add += freq[j * i]
 
            # Excluding those subsets which have
            # gcd > i but not i i.e. which have gcd
            # as multiple of i in the subset.
            # for ex: {2,3,4} cnsidering i = 2 and
            # subset we need to exclude are those
            # havng gcd as 4
            sub += subsets[j * i]
            j += 1
 
        # Number of subsets with GCD equal
        # to 'i' is pow(2, add) - 1 - sub
        subsets[i] = (1 << add) - 1 - sub
 
    for i in range(m):
        print("Number of subsets with gcd %d is %d" %
             (gcd[i], subsets[gcd[i]]))
 
# Driver Code
if __name__ == "__main__":
    gcd = [2, 3]
    arr = [9, 6, 2]
    n = len(arr)
    m = len(gcd)
    countSubsets(arr, n, gcd, m)
 
# This code is contributed by
# sanjeev2552


C#
// C# program to count
// number of subsets with
// given GCDs
using System;
using System.Collections.Generic;
class GFG{
 
// n is size of []arr and
// m is sizeof gcd[]
static void ccountSubsets(int []arr, int n,
                          int []gcd, int m)
{
  // Map to store frequency
  // of array elements
  Dictionary freq =
             new Dictionary();
 
  // Map to store number of
  // subsets with given gcd
  Dictionary subsets =
             new Dictionary();
 
  // Initialize maximum element.
  // Assumption: all array
  // elements are positive.
  int arrMax = 0;
 
  // Find maximum element in
  // array and fill frequency
  // map.
  for (int i = 0; i < n; i++)
  {
    arrMax = Math.Max(arrMax,
                      arr[i]);
    if(freq.ContainsKey(arr[i]))
    {
      freq.Add(arr[i],
      freq[arr[i]] + 1);
    }
    else
    {
      freq.Add(arr[i], 1);
    }
  }
 
  // Run a loop from max element
  // to 1 to find subsets
  // with all gcds
  for (int i = arrMax; i >= 1; i--)
  {
    int sub = 0;
    int add = 0;
    if(freq.ContainsKey(i))
      add = freq[i];
 
    // Run a loop for all
    // multiples of i
    for (int j = 2;
             j * i <= arrMax; j++)
    {
      // Sum the frequencies of
      // every element which
      // is a multiple of i
      if(freq.ContainsKey(i * j))
        add += freq[j * i];
 
      // Excluding those subsets
      // which have gcd > i but
      // not i i.e. which have
      // gcd as multiple of i in
      // the subset for ex: {2,3,4}
      // cnsidering i = 2 and
      // subset we need to exclude
      // are those havng gcd as 4
      sub += subsets[j * i];
    }
 
    // Number of subsets with GCD
    // equal to 'i' is Math.Pow(2, add)
    // - 1 - sub  
    subsets.Add(i, (1 << add) -
                1 - sub);
  }
 
  for (int i = 0; i < m; i++)
    Console.Write("Number of subsets with gcd " + 
                   gcd[i] + " is " +
                   subsets[gcd[i]] + "\n");
}
 
// Driver code
public static void Main(String[] args)
{
  int []gcd = {2, 3};
  int []arr = {9, 6, 2};
  int n = arr.Length;
  int m = gcd.Length;
  ccountSubsets(arr, n, gcd, m);
}
}
 
// This code is contributed by Rajput-Ji


输出:

Number of subsets with gcd 2 is 2
Number of subsets with gcd 3 is 1

练习:扩展上述解决方案,以便所有计算都以模1000000007为模,以避免溢出。