给定一个整数数组,任务是计算该数组所有子数组的GCD之和。数组的GCD定义为数组中所有元素的GCD。更正式地说, 。所有GCD的总和可以定义为在哪里表示从第ith个索引开始到第j个索引结束的子数组。
例子:
Input 1: N = 5, A = {1,2,3,4,5}
Output 1: 25
Explnantion:
The subarrays of length one are [1], [2], [3], [4], [5] and the sum of their GCDs is 15, similarly subarrays of length 2, are [1, 2], [2, 3], [3, 4], [4, 5], and the sum of their GCDs is 4, similarly for length 3, the sum is 3, similarly for length 4, the sum is 2, similarly for length 5, the sum is 1.
The total sum becomes 25.
Input 2: N = 6, A = {2,2,2,3,5,5}
Output 2: 41
先决条件
二元搜寻
用于在索引范围内计算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。
我们创建三个指针,将它们称为startPointer , endPointer和prevEndPointer 。最初,它们三个都指向数组的第一个元素。我们使用第一个元素的值初始化变量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)项。