📜  所有对的GCD的总和不超过N

📅  最后修改于: 2021-05-04 08:56:30             🧑  作者: Mango

给定数字N,通过选择从1到N的所有对,可以找到可以形成的所有GCD的总和。
例子:

Input  : 4
Output : 7
Explanation: 
Numbers from 1 to 4 are: 1, 2, 3, 4
Result = gcd(1,2) + gcd(1,3) + gcd(1,4) + 
         gcd(2,3) + gcd(2,4) + gcd(3,4)
       = 1 + 1 + 1 + 1 + 2 + 1
       = 7

Input  : 12
Output : 105

Input  : 1
Output : 0

Input  : 2
Output : 1

天真的方法是在另一个内部运行两个循环。逐个选择所有对,找到每对的GCD,然后找到这些GCD的总和。该方法的时间复杂度为O(N 2 * log(N))

高效方法基于以下概念:

  • 输入n的欧拉Totient函数?(n)是{1、2、3,…,n}中相对于n素数的数字的计数,即,n等于GCD(最大公约数)的数字为1。例如,?(4)= 2,?(3)= 2和?(5)=4。有2个小于或等于4的数字相对质数为4,2个小于或等于3的数字相对质数素数为3。小于或等于5的4个数相对于素数为5。

    这个想法是将给定的问题转换为欧拉Totient函数之和。

    Sum of all GCDs where j is a part of
    pair is and j is greater element in pair:
    Sumj = ?(i=1 to j-1) gcd(i, j)
    Our final result is 
    Result = ?(j=1 to N) Sumj
    
    The above equation can be written as :
    Sumj = ? g * count(g) 
    For every possible GCD 'g' of j. Here count(g)
    represents count of pairs having GCD equals to
    g. For every such pair(i, j), we can write :
     gcd(i/g, j/g) = 1
    
    We can re-write our previous equation as
    Sumj = ? d * phi(j/d) 
    For every divisor d of j and phi[] is Euler
    Totient number 
    
    Example : j = 12 and d = 3 is one of divisor 
    of j so in order to calculate the sum of count
    of all pairs having 3 as gcd we can simple write
    it as 
    => 3*phi[12/3]  
    => 3*phi[4]
    => 3*2
    => 6
    
    Therefore sum of GCDs of all pairs where 12 is 
    greater part of pair and 3 is GCD.
    GCD(3, 12) + GCD(9, 12) = 6.
    
    Complete Example : 
    N = 4
    Sum1 = 0
    Sum2 = 1 [GCD(1, 2)]
    Sum3 = 2 [GCD(1, 3) + GCD(2, 3)]
    Sum4 = 4 [GCD(1, 4) + GCD(3, 4) + GCD(2, 4)]
    
    Result = Sum1 + Sum2 + Sum3 + Sum4
           = 0 + 1 + 2 + 4
           = 7
     

    以下是上述想法的实现。我们预先计算欧拉Totient函数,并计算所有数字的结果,直到达到最大值。在实现中使用的想法是基于这篇文章的。

    C++
    // C++ approach of finding sum of GCD of all pairs
    #include
    using namespace std;
      
    #define MAX 100001
      
    // phi[i] stores euler totient function for i
    // result[j] stores result for value j
    long long phi[MAX], result[MAX];
      
    // Precomputation of phi[] numbers. Refer below link
    // for details : https://goo.gl/LUqdtY
    void computeTotient()
    {
        // Refer https://goo.gl/LUqdtY
        phi[1] = 1;
        for (int i=2; iJava
    
    // Java approach of finding 
    // sum of GCD of all pairs.
    import java.lang.*;
      
    class GFG {
          
    static final int MAX = 100001;
      
    // phi[i] stores euler totient function for i
    // result[j] stores result for value j
    static long phi[] = new long[MAX];
    static long result[] = new long[MAX];
      
    // Precomputation of phi[] numbers.
    // Refer below link for details :
    // https://goo.gl/LUqdtY
    static void computeTotient() {
          
        // Refer https://goo.gl/LUqdtY
        phi[1] = 1;
        for (int i = 2; i < MAX; i++) {
        if (phi[i] == 0) {
            phi[i] = i - 1;
            for (int j = (i << 1); j < MAX; j += i) {
            if (phi[j] == 0)
                phi[j] = j;
      
            phi[j] = (phi[j] / i) * (i - 1);
            }
        }
        }
    }
      
    // Precomputes result for all
    // numbers till MAX
    static void sumOfGcdPairs() {
          
        // Precompute all phi value
        computeTotient();
      
        for (int i = 1; i < MAX; ++i) {
              
        // Iterate throght all the 
        // divisors of i.
        for (int j = 2; i * j < MAX; ++j)
            result[i * j] += i * phi[j];
        }
      
        // Add summation of previous calculated sum
        for (int i = 2; i < MAX; i++)
        result[i] += result[i - 1];
    }
      
    // Driver code
    public static void main(String[] args) {
          
        // Function to calculate sum of 
        // all the GCD pairs
        sumOfGcdPairs();
      
        int N = 4;
        System.out.println("Summation of " + N +
                             " = " + result[N]);
        N = 12;
        System.out.println("Summation of " + N + 
                             " = " + result[N]);
        N = 5000;
        System.out.print("Summation of " + N + 
                          " = " + +result[N]);
    }
    }
      
    // This code is contributed by Anant Agarwal.


    Python3
    # Python approach of finding
    # sum of GCD of all pairs
    MAX = 100001
      
    # phi[i] stores euler 
    # totient function for 
    # i result[j] stores 
    # result for value j
    phi = [0] * MAX
    result = [0] * MAX
      
    # Precomputation of phi[]
    # numbers. Refer below link
    # for details : https://goo.gl/LUqdtY
    def computeTotient():
      
        # Refer https://goo.gl/LUqdtY
        phi[1] = 1
        for i in range(2, MAX):
            if not phi[i]:
                phi[i] = i - 1
                for j in range(i << 1, MAX, i):
                    if not phi[j]:
                        phi[j] = j
                    phi[j] = ((phi[j] // i) * 
                              (i - 1))
      
    # Precomputes result 
    # for all numbers 
    # till MAX
    def sumOfGcdPairs():
          
        # Precompute all phi value
        computeTotient()
      
        for i in range(MAX):
              
            # Iterate throght all 
            # the divisors of i.
            for j in range(2, MAX):
                if i * j >= MAX:
                    break
                result[i * j] += i * phi[j]
      
        # Add summation of 
        # previous calculated sum
        for i in range(2, MAX):
            result[i] += result[i - 1]
      
    # Driver code
    # Function to calculate 
    # sum of all the GCD pairs
    sumOfGcdPairs()
      
    N = 4
    print("Summation of",N,"=",result[N])
    N = 12
    print("Summation of",N,"=",result[N])
    N = 5000
    print("Summation of",N,"=",result[N])
      
    # This code is contributed 
    # by Sanjit_Prasad.


    C#
    // C# approach of finding 
    // sum of GCD of all pairs.
    using System;
      
    class GFG {
          
    static int MAX = 100001;
      
    // phi[i] stores euler totient
    // function for i result[j]
    // stores result for value j
    static long []phi = new long[MAX];
    static long []result = new long[MAX];
      
    // Precomputation of phi[] numbers.
    // Refer below link for details :
    // https://goo.gl/LUqdtY
    static void computeTotient() {
          
        // Refer https://goo.gl/LUqdtY
        phi[1] = 1;
        for (int i = 2; i < MAX; i++) {
        if (phi[i] == 0) {
            phi[i] = i - 1;
            for (int j = (i << 1); j < MAX; j += i) {
            if (phi[j] == 0)
                phi[j] = j;
      
            phi[j] = (phi[j] / i) * (i - 1);
            }
        }
        }
    }
      
    // Precomputes result for all
    // numbers till MAX
    static void sumOfGcdPairs() {
          
        // Precompute all phi value
        computeTotient();
      
        for (int i = 1; i < MAX; ++i) {
              
        // Iterate throght all the 
        // divisors of i.
        for (int j = 2; i * j < MAX; ++j)
            result[i * j] += i * phi[j];
        }
      
        // Add summation of previous 
        // calculated sum
        for (int i = 2; i < MAX; i++)
        result[i] += result[i - 1];
    }
      
    // Driver code
    public static void Main() {
          
        // Function to calculate sum of 
        // all the GCD pairs
        sumOfGcdPairs();
      
        int N = 4;
        Console.WriteLine("Summation of " + N +
                          " = " + result[N]);
        N = 12;
        Console.WriteLine("Summation of " + N + 
                          " = " + result[N]);
        N = 5000;
        Console.Write("Summation of " + N + 
                      " = " + +result[N]);
    }
    }
      
    // This code is contributed by Nitin Mittal.


    PHP


    输出:

    Summation of 4 = 7
    Summation of 12 = 105
    Summation of 5000 = 61567426
    

    时间复杂度: O(MAX * log(log MAX))
    辅助空间: O(MAX)

    参考:
    https://www.quora.com/How-can-I-solve-the-problem-GCD-Extreme-on-SPOJ-SPOJ-com-Problem-GCDEX