所以,我在接受采访时被问到这个问题。给定一组数字(不一定是不同的),我必须找到给定数字组的所有可能子集的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。 但是,如果n很大,那么将有2 ^ n个子集,这将不能最佳地工作。我该如何优化呢?
答案 0 :(得分:1)
假设每个数组元素都是1..U范围内的整数,对于某些U.
设f(x)为GCD(x)的子集数。该问题的解决方案是所有不同因子1< = d< = U的总和d ^ f(d)。
设g(x)是可被x整除的数组元素的数量。
我们有
f(x) = 2^g(x) - SUM(x | y, f(y))
我们可以通过枚举每个数组元素的所有除数来计算O(n * sqrt(U))中的g(x)。通过以直接的方式枚举x的每个倍数,可以在O(U log U)中从高值到低值计算f(x)。
答案 1 :(得分:1)
先决条件:
费马的小定理(也有一个广义定理),简单的数学,模幂运算
说明:符号:A []代表我们的输入数组
显然约束1< = N< = 10 ^ 5,告诉我你需要一个O(N * LOG N)解决方案,不要试图认为DP因为它的复杂性根据我将是N * max(A [i])即约。 10 ^ 5 * 10 ^ 6。为什么?因为你需要子集的GCD来进行转换。
好的,继续前进
我们可以考虑使用相同的GCD对子集进行分组,以便提高复杂性。
所以,让迭代器从10 ^ 6递减到1试图用GCD制作集合!
现在用GCD制作子集(i)我可以用任何i * j来组合它,其中j是非负整数。为什么?
GCD(i,i * j)= i
现在,
我们可以为任何元素构建一个频率表,因为数字是可以访问的!
现在,在比赛期间,我所做的是,将gcd(i)的子集数保持在f2 [i]
因此我们所做的是来自j * i的所有元素的总和频率,其中j从1变化到地面(i / j) 现在带有公约数(而不是GCD)的子集为i(2 ^ sum - 1)。
现在我们必须从这个总和中减去GCD大于i的子集,并将i作为gcd的公约数作为i。
这也可以在同一个循环中通过取f2 [i * j]求和,其中j从1变化到地面(i / j)
现在GCD的子集i等于2 ^ sum -1 - f2 [ij]的总和恰好乘以i(子集的数量与GCD的次数i次)即幂(i,2 ^ sum -1 - f2的总和[ij])。但现在计算这个指数部分可以溢出,但你可以用给定MOD-1的%,因为MOD是素数! (费马小定理)使用模幂运算
以下是我的代码片段,因为我不确定我们现在可以发布代码了吗?
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让事情变得复杂,我觉得我们可以在没有F2的情况下通过不采用j = 1来做到这一点。但是没关系我没想到它这是我是如何设法获得AC的。