📜  计算所有子阵列上的GCD之和

📅  最后修改于: 2021-05-06 10:10:52             🧑  作者: Mango

给定一个整数数组,任务是计算该数组所有子数组的GCD之和。数组的GCD定义为数组中所有元素的GCD。更正式地说, GCD(A[n]) = GCD(A_1, A_2, A_3....A_n)  。所有GCD的总和可以定义为\sum_{i=1}^{n}\sum_{j=i}^{n} GCD(A_{ij})  在哪里A_{ij}  表示从第ith个索引开始到第j个索引结束的子数组。
例子:

先决条件
二元搜寻
用于在索引范围内计算GCD的段树方法
用于在指数范围内计算GCD的稀疏表

天真的方法(O(n ^ 3)复杂度)
我们可以找出O(n ^ 2)复杂度的每个子数组,并遍历每个子数组以找到该子数组的GCD并将其添加到总答案中。
下面是上述方法的实现:

C++
// C++ program to find
// Sum of GCD over all subarrays.
 
#include 
using namespace std;
 
// Utility function to calculate
// sum of gcd of all sub-arrays.
 
int findGCDSum(int n, int a[])
{
    int GCDSum = 0;
    int tempGCD = 0;
    for (int i = 0; i < n; i++) {
        // Fixing the starting index of a subarray
        for (int j = i; j < n; j++) {
            // Fixing the ending index of a subarray
            tempGCD = 0;
            for (int k = i; k <= j; k++) {
                // Finding the GCD of this subarray
                tempGCD = __gcd(tempGCD, a[k]);
            }
            // Adding this GCD in our sum
            GCDSum += tempGCD;
        }
    }
    return GCDSum;
}
 
// Driver Code
int main()
{
    int n = 5;
    int a[] = { 1, 2, 3, 4, 5 };
    int totalSum = findGCDSum(n, a);
    cout << totalSum << "\n";
}


Java
// Java program to find
// Sum of GCD over all subarrays.
class GFG
{
 
// Utility function to calculate
// sum of gcd of all sub-arrays.
static int findGCDSum(int n, int a[])
{
    int GCDSum = 0;
    int tempGCD = 0;
    for (int i = 0; i < n; i++)
    {
        // Fixing the starting index of a subarray
        for (int j = i; j < n; j++)
        {
            // Fixing the ending index of a subarray
            tempGCD = 0;
            for (int k = i; k <= j; k++)
            {
                // Finding the GCD of this subarray
                tempGCD = __gcd(tempGCD, a[k]);
            }
             
            // Adding this GCD in our sum
            GCDSum += tempGCD;
        }
    }
    return GCDSum;
}
 
static int __gcd(int a, int b)
{
    return b == 0 ? a : __gcd(b, a % b);    
}
 
// Driver Code
public static void main(String[] args)
{
    int n = 5;
    int a[] = { 1, 2, 3, 4, 5 };
    int totalSum = findGCDSum(n, a);
    System.out.print(totalSum + "\n");
}
}
 
// This code is contributed by 29AjayKumar


Python3
# Python3 program to find
# Sum of GCD over all subarrays.
 
# Utility function to calculate
# sum of gcd of all sub-arrays.
def findGCDSum(n, a):
    GCDSum = 0;
    tempGCD = 0;
    for i in range(n):
         
        # Fixing the starting index of a subarray
        for j in range(i, n):
             
            # Fixing the ending index of a subarray
            tempGCD = 0;
            for k in range(i, j + 1):
                 
                # Finding the GCD of this subarray
                tempGCD = __gcd(tempGCD, a[k]);
                 
            # Adding this GCD in our sum
            GCDSum += tempGCD;
 
    return GCDSum;
 
def __gcd(a, b):
    return a if(b == 0 ) else __gcd(b, a % b);    
 
# Driver Code
if __name__ == '__main__':
    n = 5;
    a = [1, 2, 3, 4, 5];
    totalSum = findGCDSum(n, a);
    print(totalSum);
 
# This code is contributed by PrinciRaj1992


C#
// C# program to find
// Sum of GCD over all subarrays.
using System;
 
class GFG
{
 
// Utility function to calculate
// sum of gcd of all sub-arrays.
static int findGCDSum(int n, int []a)
{
    int GCDSum = 0;
    int tempGCD = 0;
    for (int i = 0; i < n; i++)
    {
        // Fixing the starting index of a subarray
        for (int j = i; j < n; j++)
        {
            // Fixing the ending index of a subarray
            tempGCD = 0;
            for (int k = i; k <= j; k++)
            {
                // Finding the GCD of this subarray
                tempGCD = __gcd(tempGCD, a[k]);
            }
             
            // Adding this GCD in our sum
            GCDSum += tempGCD;
        }
    }
    return GCDSum;
}
 
static int __gcd(int a, int b)
{
    return b == 0 ? a : __gcd(b, a % b);    
}
 
// Driver Code
public static void Main(String[] args)
{
    int n = 5;
    int []a = { 1, 2, 3, 4, 5 };
    int totalSum = findGCDSum(n, a);
    Console.Write(totalSum + "\n");
}
}
 
// This code is contributed by Rajput-Ji


Javascript


C++
// C++ program to find Sum
// of GCD over all subarrays
 
#include 
using namespace std;
 
//int a[100001];
int SparseTable[100001][51];
 
// Build Sparse Table
void buildSparseTable(int a[], int n)
{
    for (int i = 0; i < n; i++) {
        SparseTable[i][0] = a[i];
    }
    // Building the Sparse Table for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++) {
        for (int i = 0; i <= n - (1 << j); i++) {
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                    SparseTable[i + (1 << (j - 1))][j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = int(log2(R - L + 1));
     
    returnValue = __gcd(SparseTable[L][j],
                    SparseTable[R - (1 << j) + 1][j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
int nextPosition(int tempGCD, int startPointer,
                            int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low) {
         
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD) {
            nextPos = mid;
            low = mid + 1;
        }
        else {
            high = mid - 1;
        }
    }
     
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
int calculateSum(int a[], int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer, prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++) {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n) {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                            prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer - prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n) {
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
// Driver Code
int main()
{
    int n = 6;
     
    int a[] = {2, 2, 2, 3, 5, 5};
     
    cout << calculateSum(a, n) << "\n";
     
    return 0;
}


Java
// Java program to find Sum
// of GCD over all subarrays
class GFG
{
 
//int a[100001];
static int [][]SparseTable = new int[100001][51];
 
// Build Sparse Table
static void buildSparseTable(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        SparseTable[i][0] = a[i];
    }
     
    // Building the Sparse Table
    // for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++)
    {
        for (int i = 0; i <= n - (1 << j); i++)
        {
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                     SparseTable[i + (1 << (j - 1))][j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
static int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = (int) (Math.log(R - L + 1));
     
    returnValue = __gcd(SparseTable[L][j],
         SparseTable[R - (1 << j) + 1][j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
static int nextPosition(int tempGCD, int startPointer,
                        int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low)
    {
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD)
        {
            nextPos = mid;
            low = mid + 1;
        }
        else
        {
            high = mid - 1;
        }
    }
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
static int calculateSum(int a[], int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer,
        prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++)
    {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n)
        {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                         prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer -
                         prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n)
            {
                 
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
static int __gcd(int a, int b)
{
    return b == 0? a:__gcd(b, a % b);    
}
 
// Driver code
public static void main(String[] args)
{
    int n = 6;
     
    int a[] = {2, 2, 2, 3, 5, 5};
     
    System.out.println(calculateSum(a, n));
}
}
 
// This code is contributed by PrinciRaj1992


Python3
# Python3 program to find Sum
# of GCD over all subarrays
from math import gcd as __gcd,log,floor
SparseTable = [ [0 for i in range(51)] for i in range(100001)]
 
# Build Sparse Table
def buildSparseTable(a, n):
    for i in range(n):
        SparseTable[i][0] = a[i]
 
    # Building the Sparse Table for GCD[L, R] Queries
    for j in range(1,20):
        for i in range(n - (1 << j)+1):
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                                SparseTable[i + (1 << (j - 1))][j - 1])
 
# Utility Function to calculate GCD in range [L,R]
def queryForGCD(L, R):
 
    # Calculating where the answer is
    # stored in our Sparse Table
    j = floor(log(R - L + 1, 2))
 
    returnValue = __gcd(SparseTable[L][j],
                SparseTable[R - (1 << j) + 1][j])
 
    return returnValue
 
 
# Utility Function to find next-farther
# position where gcd is same
def nextPosition(tempGCD, startPointer,prevEndPointer, n):
    high = n - 1
    low = prevEndPointer
    mid = prevEndPointer
    nextPos = prevEndPointer
 
    # BinarySearch for Next Position
    # for EndPointer
    while (high >= low):
 
        mid = ((high + low) >> 1)
 
        if (queryForGCD(startPointer, mid) == tempGCD):
            nextPos = mid
            low = mid + 1
        else:
            high = mid - 1
 
    return nextPos + 1
 
# Utility function to calculate
# sum of gcd
def calculateSum(a, n):
    buildSparseTable(a, n)
 
    tempAns = 0
 
    for i in range(n):
         
        # Initialising all the values
        endPointer = i
        startPointer = i
        prevEndPointer = i
        tempGCD = a[i]
        while (endPointer < n):
 
            # Finding the next position for endPointer
            endPointer = nextPosition(tempGCD,
                        startPointer,prevEndPointer, n)
 
            # Adding the suitable sum to our answer
            tempAns += ((endPointer - prevEndPointer) * tempGCD)
 
            # Changing prevEndPointer
            prevEndPointer = endPointer
 
            if (endPointer < n):
                 
                # Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer])
 
    return tempAns
 
# Driver code
if __name__ == '__main__':
    n = 6
 
    a = [2, 2, 2, 3, 5, 5]
 
    print(calculateSum(a, n))
 
# This code is contributed by mohit kumar 29


C#
// C# program to find Sum
// of GCD over all subarrays
using System;
 
class GFG
{
 
//int a[100001];
static int [,]SparseTable = new int[100001,51];
 
// Build Sparse Table
static void buildSparseTable(int []a, int n)
{
    for (int i = 0; i < n; i++)
    {
        SparseTable[i,0] = a[i];
    }
     
    // Building the Sparse Table
    // for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++)
    {
        for (int i = 0; i <= n - (1 << j); i++)
        {
            SparseTable[i,j] = __gcd(SparseTable[i,j - 1],
                    SparseTable[i + (1 << (j - 1)),j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
static int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = (int) (Math.Log(R - L + 1));
     
    returnValue = __gcd(SparseTable[L,j],
        SparseTable[R - (1 << j) + 1,j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
static int nextPosition(int tempGCD, int startPointer,
                        int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low)
    {
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD)
        {
            nextPos = mid;
            low = mid + 1;
        }
        else
        {
            high = mid - 1;
        }
    }
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
static int calculateSum(int []a, int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer,
        prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++)
    {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n)
        {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                        prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer -
                        prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n)
            {
                 
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
static int __gcd(int a, int b)
{
    return b == 0? a:__gcd(b, a % b);    
}
 
// Driver code
public static void Main(String[] args)
{
    int n = 6;
     
    int []a = {2, 2, 2, 3, 5, 5};
     
    Console.WriteLine(calculateSum(a, n));
}
}
 
// This code contributed by PrinciRaj1992


输出:
25

我们可以优化计算子数组GCD的部分,可以使用段树或稀疏表将复杂度优化为O(n ^ 2 * logn)(对于段树)或O(n ^ 2)(对于稀疏表)
高效方法(O(n *(logn)^ 2)复杂度)
这种方法利用了以下观察优势:在向数组添加新元素时,数组的新GCD将始终小于或等于添加元素之前数组的先前GCD。
我们创建三个指针,将它们称为startPointerendPointerprevEndPointer 。最初,它们三个都指向数组的第一个元素。我们使用第一个元素的值初始化变量tempGCD 。现在,我们将找到从第一个元素开始的所有子数组的GCD的总和。
现在,根据我们之前的观察,如果将endPointer向右移动一个位置,并计算由startPointer和endPointer指向的这两个元素的GCD,它将始终小于或等于tempGCD。因此,如果我们想找出GCD作为tempGCD的子数组的数量,则需要找到endPointer的合适位置,其中从startPointer开始到endPointer结束的子数组的GCD值将小于tempGCD,并且该值endPointer的数量应尽可能小,然后prevEndPointer和endPointer的差将为我们提供其GCD为tempGCD的子数组的数量。现在,我们可以将此值(tempGCD *(endPointer-prevEndPointer))添加到变量finalAns中,该值表示这些子阵状数组的GCD的总和,该变量存储所有子数组的GCD的总和。
现在问题仍然存在,我们如何找到GCD降低的endPointer的合适位置?那就是使用Binary Search的地方,我们已经确定了数组的起点,我们需要改变终点,我们将它们称为L和R,因此对于任何R。我们将N初始化为N,将Low初始化为prevEndPointer,并且mid为(high + low)/ 2,现在,如果我们检查GCD [L,mid]的值,则将其与tempGCD的值进行比较,如果小于它,则R可能是endPointer的合适位置,但可能是某些较小的值可能成为我们的答案,因此我们将高更改为中1,如果发现GCD [L,mid]等于tempGCD,则应将低更改为中+1,并且mid + 1的值可能是答案,因此我们将mid的值存储在变量nextPos中。最后,我们返回nextPos + 1的值。
可以使用O(logN)复杂度的分段树或O(1)复杂度的稀疏表有效地计算GCD [L,mid]的值。
这种类型的二进制搜索为我们找到了EndPointer的合适位置。找到该位置并添加到finalAns之后,我们将prevEndPointer更改为endPointer,将tempGCD更改为GCD [startPointer,endPointer] ,然后再次开始查找下一个endPointer的过程。一旦endPointer的值变为N,此操作将停止,然后我们需要将startPointer移到右侧,这将计算从第二个元素开始的所有子数组的GCD之和。这将一直持续到startPointer的值变为N为止。
下面是上述方法的实现:

C++

// C++ program to find Sum
// of GCD over all subarrays
 
#include 
using namespace std;
 
//int a[100001];
int SparseTable[100001][51];
 
// Build Sparse Table
void buildSparseTable(int a[], int n)
{
    for (int i = 0; i < n; i++) {
        SparseTable[i][0] = a[i];
    }
    // Building the Sparse Table for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++) {
        for (int i = 0; i <= n - (1 << j); i++) {
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                    SparseTable[i + (1 << (j - 1))][j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = int(log2(R - L + 1));
     
    returnValue = __gcd(SparseTable[L][j],
                    SparseTable[R - (1 << j) + 1][j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
int nextPosition(int tempGCD, int startPointer,
                            int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low) {
         
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD) {
            nextPos = mid;
            low = mid + 1;
        }
        else {
            high = mid - 1;
        }
    }
     
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
int calculateSum(int a[], int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer, prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++) {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n) {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                            prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer - prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n) {
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
// Driver Code
int main()
{
    int n = 6;
     
    int a[] = {2, 2, 2, 3, 5, 5};
     
    cout << calculateSum(a, n) << "\n";
     
    return 0;
}

Java

// Java program to find Sum
// of GCD over all subarrays
class GFG
{
 
//int a[100001];
static int [][]SparseTable = new int[100001][51];
 
// Build Sparse Table
static void buildSparseTable(int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        SparseTable[i][0] = a[i];
    }
     
    // Building the Sparse Table
    // for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++)
    {
        for (int i = 0; i <= n - (1 << j); i++)
        {
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                     SparseTable[i + (1 << (j - 1))][j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
static int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = (int) (Math.log(R - L + 1));
     
    returnValue = __gcd(SparseTable[L][j],
         SparseTable[R - (1 << j) + 1][j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
static int nextPosition(int tempGCD, int startPointer,
                        int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low)
    {
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD)
        {
            nextPos = mid;
            low = mid + 1;
        }
        else
        {
            high = mid - 1;
        }
    }
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
static int calculateSum(int a[], int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer,
        prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++)
    {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n)
        {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                         prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer -
                         prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n)
            {
                 
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
static int __gcd(int a, int b)
{
    return b == 0? a:__gcd(b, a % b);    
}
 
// Driver code
public static void main(String[] args)
{
    int n = 6;
     
    int a[] = {2, 2, 2, 3, 5, 5};
     
    System.out.println(calculateSum(a, n));
}
}
 
// This code is contributed by PrinciRaj1992

Python3

# Python3 program to find Sum
# of GCD over all subarrays
from math import gcd as __gcd,log,floor
SparseTable = [ [0 for i in range(51)] for i in range(100001)]
 
# Build Sparse Table
def buildSparseTable(a, n):
    for i in range(n):
        SparseTable[i][0] = a[i]
 
    # Building the Sparse Table for GCD[L, R] Queries
    for j in range(1,20):
        for i in range(n - (1 << j)+1):
            SparseTable[i][j] = __gcd(SparseTable[i][j - 1],
                                SparseTable[i + (1 << (j - 1))][j - 1])
 
# Utility Function to calculate GCD in range [L,R]
def queryForGCD(L, R):
 
    # Calculating where the answer is
    # stored in our Sparse Table
    j = floor(log(R - L + 1, 2))
 
    returnValue = __gcd(SparseTable[L][j],
                SparseTable[R - (1 << j) + 1][j])
 
    return returnValue
 
 
# Utility Function to find next-farther
# position where gcd is same
def nextPosition(tempGCD, startPointer,prevEndPointer, n):
    high = n - 1
    low = prevEndPointer
    mid = prevEndPointer
    nextPos = prevEndPointer
 
    # BinarySearch for Next Position
    # for EndPointer
    while (high >= low):
 
        mid = ((high + low) >> 1)
 
        if (queryForGCD(startPointer, mid) == tempGCD):
            nextPos = mid
            low = mid + 1
        else:
            high = mid - 1
 
    return nextPos + 1
 
# Utility function to calculate
# sum of gcd
def calculateSum(a, n):
    buildSparseTable(a, n)
 
    tempAns = 0
 
    for i in range(n):
         
        # Initialising all the values
        endPointer = i
        startPointer = i
        prevEndPointer = i
        tempGCD = a[i]
        while (endPointer < n):
 
            # Finding the next position for endPointer
            endPointer = nextPosition(tempGCD,
                        startPointer,prevEndPointer, n)
 
            # Adding the suitable sum to our answer
            tempAns += ((endPointer - prevEndPointer) * tempGCD)
 
            # Changing prevEndPointer
            prevEndPointer = endPointer
 
            if (endPointer < n):
                 
                # Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer])
 
    return tempAns
 
# Driver code
if __name__ == '__main__':
    n = 6
 
    a = [2, 2, 2, 3, 5, 5]
 
    print(calculateSum(a, n))
 
# This code is contributed by mohit kumar 29

C#

// C# program to find Sum
// of GCD over all subarrays
using System;
 
class GFG
{
 
//int a[100001];
static int [,]SparseTable = new int[100001,51];
 
// Build Sparse Table
static void buildSparseTable(int []a, int n)
{
    for (int i = 0; i < n; i++)
    {
        SparseTable[i,0] = a[i];
    }
     
    // Building the Sparse Table
    // for GCD[L, R] Queries
    for (int j = 1; j <= 19; j++)
    {
        for (int i = 0; i <= n - (1 << j); i++)
        {
            SparseTable[i,j] = __gcd(SparseTable[i,j - 1],
                    SparseTable[i + (1 << (j - 1)),j - 1]);
        }
    }
}
 
// Utility Function to calculate GCD in range [L,R]
static int queryForGCD(int L, int R)
{
    int returnValue;
     
    // Calculating where the answer is
    // stored in our Sparse Table
    int j = (int) (Math.Log(R - L + 1));
     
    returnValue = __gcd(SparseTable[L,j],
        SparseTable[R - (1 << j) + 1,j]);
                     
    return returnValue;
}
 
// Utility Function to find next-farther
// position where gcd is same
static int nextPosition(int tempGCD, int startPointer,
                        int prevEndPointer, int n)
{
    int high = n - 1;
    int low = prevEndPointer;
    int mid = prevEndPointer;
    int nextPos = prevEndPointer;
     
    // BinarySearch for Next Position
    // for EndPointer
    while (high >= low)
    {
        mid = ((high + low) >> 1);
         
        if (queryForGCD(startPointer, mid) == tempGCD)
        {
            nextPos = mid;
            low = mid + 1;
        }
        else
        {
            high = mid - 1;
        }
    }
    return nextPos + 1;
}
 
// Utility function to calculate
// sum of gcd
static int calculateSum(int []a, int n)
{
    buildSparseTable(a, n);
     
    int endPointer, startPointer,
        prevEndPointer, tempGCD;
     
    int tempAns = 0;
     
    for (int i = 0; i < n; i++)
    {
        // Initialising all the values
        endPointer = i;
        startPointer = i;
        prevEndPointer = i;
        tempGCD = a[i];
        while (endPointer < n)
        {
 
            // Finding the next position for endPointer
            endPointer = nextPosition(tempGCD, startPointer,
                                        prevEndPointer, n);
 
            // Adding the suitable sum to our answer
            tempAns += ((endPointer -
                        prevEndPointer) * tempGCD);
 
            // Changing prevEndPointer
            prevEndPointer = endPointer;
 
            if (endPointer < n)
            {
                 
                // Recalculating tempGCD
                tempGCD = __gcd(tempGCD, a[endPointer]);
            }
        }
    }
    return tempAns;
}
 
static int __gcd(int a, int b)
{
    return b == 0? a:__gcd(b, a % b);    
}
 
// Driver code
public static void Main(String[] args)
{
    int n = 6;
     
    int []a = {2, 2, 2, 3, 5, 5};
     
    Console.WriteLine(calculateSum(a, n));
}
}
 
// This code contributed by PrinciRaj1992
输出:
41

时间复杂度:O(N * log(max(A [i])* log(N))
上述解决方案的时间复杂度包括知道二进制搜索将被调用多少次的知识,因此我们需要知道endPointer的值可能改变多少次。这个值大约是log(A [i]) ,因为对于任何数字X,当与其他数字组合时,其GCD可以减少的次数是其任何主除数的最高幂的值。因此,总时间复杂度约为O(N * log(max(A [i])* log(N)) ,其中另一个logN因子归因于二进制搜索。如果使用细分,则使用稀疏表时就是这种情况用于GCD查询的树,将出现另一个log(N)项。