【问题标题】:Finding GCD of a set of numbers?找到一组数字的 GCD?
【发布时间】:2026-02-15 21:10:02
【问题描述】:

所以,我在一次采访中被问到这个问题。给定一组数字(不一定不同),我必须找到给定数字组所有可能子集的 GCD 的乘积。

我告诉面试官的方法:

1. Recursively generate all possible subsets of the given set.
2a. For a particular subset of the given set:
2b. Find GCD of that subset using the Euclid's Algorithm.
3. Multiply it in the answer being obtained.  

假设空集的 GCD 为 1。 但是,将有 2^n 个子集,如果 n 很大,这将无法以最佳方式工作。如何优化它?

【问题讨论】:

  • “模数”是什么意思?什么是除数?
  • 通过 3 个步骤构建 a 子集。这应该如何找到所有子集?
  • 另外,面试官可能想要调整他们的术语。允许重复的无序列表通常称为“multiset”或“bag”。
  • @Rhymoid,我的错。我试图用偶数和奇数来划分它,但什么也不能形成。
  • 这是来自正在进行的比赛:ACM-ICPC Asia-Amritapuri 地区。 s3.amazonaws.com/codechef_shared/download/ICPC/2015/… 从这里开始的第二个问题。目前比赛正在进行中。所以我怀疑你在采访中被问到这个问题。

标签: c++ algorithm


【解决方案1】:

假设每个数组元素都是 1..U 范围内的整数,对于某些 U。

令 f(x) 为具有 GCD(x) 的子集数。问题的解决方案是所有不同因子 1

设 g(x) 为可被 x 整除的数组元素个数。

我们有

f(x) = 2^g(x) - SUM(x | y, f(y))

我们可以通过枚举每个数组元素的所有除数来计算 O(n * sqrt(U)) 中的 g(x)。 f(x) 可以在 O(U log U) 中从高值到低值计算,通过以简单的方式枚举 x 的每个倍数。

【讨论】:

    【解决方案2】:

    先决条件

    费马小定理(也有广义定理)、简单数学、模幂运算

    解释:符号:A[] 代表我们的输入数组

    显然约束 1

    好的,继续

    我们可以考虑将具有相同 GCD 的子集组合起来,以增加复杂度。

    所以,让我们将迭代器 i 从 10^6 递减到 1 以尝试使用 GCD i 创建集合!

    现在要使用 GCD(i) 创建子集,我可以将它与任何 i*j 组合在一起,其中 j 是非负整数。为什么?

    GCD(i , i*j ) = i

    现在,

    我们可以为任何元素建立一个频率表,因为这个数字很容易达到!

    现在,在比赛期间,我所做的是,将 gcd(i) 的子集数量保持在 f2[i]

    因此我们所做的是 j*i 中所有元素的总频率,其中 j 从 1 变化到 floor(i/j) 现在具有公约数(而不是 GCD)的子集,因为 i 是 (2^sum - 1)。

    现在我们必须从这个总和中减去 GCD 大于 i 并且 i 作为 gcd as i 的公约数的子集。

    这也可以在同一个循环中通过对 f2[i*j] 求和来完成,其中 j 从 1 变化到 floor(i/j)

    现在 GCD i 的子集等于 2^sum -1 - f2[ij] 的总和只需将 i (具有 GCD i 的子集的数量)相乘,即功率(i,2^sum -1 - f2 的总和[j]) 。但是现在要计算这个指数部分可能会溢出,但是您可以使用给定的 MOD-1 取它的百分比,因为 MOD 是素数! (费马小定理)使用模幂运算

    这是我的代码的 sn-p,因为我不确定我们现在可以发布代码!

    for(i=max_ele; i >= 1;--i)
                {
                    to_add=F[i];
                    to_subtract = 0 ;
                    for(j=2 ;j*i <= max_ele;++j)
                        {
                            to_add+=F[j*i];
                            to_subtract+=F2[j*i];
                            to_subtract>=(MOD-1)?(to_subtract%=(MOD-1)):0;
                        }
    
                    subsets = (((power(2 , to_add , MOD-1) ) - 1) - to_subtract)%(MOD-1) ;
    
                if(subsets<0)
                    subsets = (subsets%(MOD-1) +MOD-1)%(MOD-1);
    
                ans  = ans * power(i , subsets , MOD);
                F2[i]= subsets;
                ans %=MOD;
            }
    

    我觉得我用 F2 让事情变得复杂了,我觉得我们可以通过不采用 j = 1 来完成没有 F2 的事情。但没关系我没有考虑过,这就是我设法获得 AC 的方法.

    【讨论】: