我如何准确地解决这个GCD?

时间:2015-10-11 13:12:19

标签: c++ algorithm

https://www.codechef.com/problems/MAXGCD

Chef有一个由N个整数组成的集合。如果子集具有两个或更多元素,Chef会调用此集合的子集。他将所有好的子集表示为S1,S2,S3,...,S2N-N-1。现在,他将每个良好子集Si的元素的GCD表示为Gi。 Chef希望找到最大的Gi。

输入

输入的第一行包含一个整数T,表示测试用例的数量。 T测试用例的描述如下。" 每个测试用例的第一行包含一个整数N,表示集合中的元素数。第二行包含N个空格分隔的整数A1,A2,...,AN,表示集合的元素。

输出

对于每个测试用例,输出最大Gi

我的解决方案:

  1. 我生成给定集合的所有可能子集。
  2. 我使用Euclid算法
  3. 计算每组的GCD
  4. 我试图找到所有这些中的最大值。
  5. 这是我制作所有可能子集的代码:

    vector< vector<int> > getAllSubsets(vector<int> set)
    {
        vector< vector<int> > subset;
        vector<int> empty;
        subset.push_back( empty );
    
        for (int i = 0; i < set.size(); i++)
        {
            vector< vector<int> > subsetTemp = subset;
    
            for (int j = 0; j < subsetTemp.size(); j++)
                subsetTemp[j].push_back( set[i] );
    
            for (int j = 0; j < subsetTemp.size(); j++)
                subset.push_back( subsetTemp[j] );
        }
        return subset;
    }
    

    但是,我采用这种方法时会得到TLE。我在哪里错了?

2 个答案:

答案 0 :(得分:2)

一个优化是您永远不需要考虑大于2个元素的子集。这是因为如果你添加另一个元素,GCD只能减少

这会导致O(n^2)算法。问题陈述说n可以和100 000一样大,所以我们需要做得更好。

问题还在于给定的值最多为500 000,因此GCD不能超过此值。

count[i] = how many times the value i appears in the array

然后我们可以应用与Sieve of Eratosthenes类似的内容:对于固定值v,看看您是否可以找到两个v的倍数(计数总和[multiple_of_v]&gt; 1 )。如果可以,那么你可以拥有v的GCD。跟踪你能找到的最大值。

伪代码:

V = max(given array)
cnt[i] = how many times value i occurs in given array

for v = V down to 1:
  num_multiples_v = 0
  for j = v up to V:
    num_multiples_v += cnt[j]

  if num_multiples_v > 1: # TODO: break the inner loop when this is true
    print v as solution
    return

复杂性将是O(V log log V),这应该非常快。

答案 1 :(得分:0)

您不需要所有子集。

gcd的一些基本属性:

gcd(a,b) == gcd(b,a)
gcd(a,b) <= a  
gcd(a,b) <= b  
gcd(a,b,c) == gcd(a,gcd(b,c)) == gcd(gcd(a,b),c)  

通过这个,很容易显示

gcd(a,b) >= gcd(a,b,c) >= gcd(a,b,c,d)...

表示任何自然数a,b,c,d。

您想要找到具有最大值的(其中一个)子集。 GCD。根据上面的规则,这个子集中的一个具有恰好两个元素(假设整个集合具有至少两个元素)。因此,第一个优化是抛弃子集生成并使其类似

max = 0
for all set elements "a"
{
    for all set elements "b"
    {
        if(gcd(a,b) > max)
            max = gcd(a,b)
    }
}

如果仍然不够,首先将集合表格从最大元素排序到最小元素,对于在循环中计算的每个gcd,删除小于计算值的每个集合元素。