📌  相关文章
📜  计算由奇数个除数组成的数组元素总和的查询

📅  最后修改于: 2021-09-07 04:40:40             🧑  作者: Mango

给定一个由N 个正整数组成的数组arr[]和一个由{L, R}形式的Q 个查询组成的数组Query[][2] ,任务是找到范围[L, R] ,有奇数个除数。

例子:

朴素的方法:解决给定问题的最简单方法是为每个查询在范围[L, R]上遍历给定数组arr[]并找到范围[L, R] 中具有奇数个元素的总和除数,并打印结果和。

时间复杂度: O(Q * N *√N)
辅助空间: O(1)

高效方法:上述方法也可以基于以下观察进行优化:

  • 仅当数字是完全平方数时,除数的数量才为奇数。
  • 因此,可以通过将除数不是奇数的整数替换为 0 来解决问题。然后,构建一个段树,找到范围内元素的总和来回答查询。

请按照以下步骤解决问题:

  • 遍历给定的数组arr[]并将不是完全平方的整数替换为0
  • 构建一个段树来回答范围之间的求和查询。
  • 遍历所有Q查询,对于每个查询,从段树中获取特定范围的总和。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
 
// Function to get the middle index
// from the given ranges
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}
 
// Recursive function to find the sum
// of values in the given range of
// the array
int getSumUtil(int* st, int ss, int se,
               int qs, int qe, int si)
{
 
    // If segment of this node is a
    // part of given range, then
    // return the sum of the segment
    if (qs <= ss && qe >= se)
        return st[si];
 
    // If segment of this node is
    // outside the given range
    if (se < qs || ss > qe)
        return 0;
 
    // If a part of this segment
    // overlaps the given range
    int mid = getMid(ss, se);
 
    return getSumUtil(st, ss, mid,
                      qs, qe, 2 * si + 1)
           + getSumUtil(st, mid + 1,
                        se, qs, qe,
                        2 * si + 2);
}
 
// Function to find the sum of elements
// in the range from index qs (query
// start) to qe (query end)
int getSum(int* st, int n, int qs, int qe)
{
    // Invalid ranges
    if (qs < 0 || qe > n - 1 || qs > qe) {
        cout << "Invalid Input";
        return -1;
    }
 
    return getSumUtil(st, 0, n - 1, qs, qe, 0);
}
 
// Recursive function to construct the
// Segment Tree for array[ss..se]. si
// is index of current node in tree st
int constructSTUtil(int arr[], int ss,
                    int se, int* st,
                    int si)
{
    // If there is one element
    // in the array
    if (ss == se) {
        st[si] = arr[ss];
        return arr[ss];
    }
 
    int mid = getMid(ss, se);
 
    // Recur for left and right
    // subtrees and store the sum
    // of values in this node
    st[si] = constructSTUtil(arr, ss, mid,
                             st, si * 2 + 1)
             + constructSTUtil(arr, mid + 1,
                               se, st,
                               si * 2 + 2);
    return st[si];
}
 
// Function to construct segment tree
// from the given array
int* constructST(int arr[], int n)
{
    // Allocate memory for the segment
    // tree Height of segment tree
    int x = (int)(ceil(log2(n)));
 
    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;
 
    // Allocate memory
    int* st = new int[max_size];
 
    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0);
 
    // Return the constructed
    // segment tree
    return st;
}
 
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int arr[],
                    vector > Query)
{
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int sq = sqrt(arr[i]);
 
        // Replace elements that are
        // not perfect squares with 0
        if (sq * sq != arr[i])
            arr[i] = 0;
    }
 
    // Build segment tree from the
    // given array
    int* st = constructST(arr, n);
 
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
        int l = Query[i].first;
        int r = Query[i].second;
 
        // Print sum of values in
        // array from index l to r
        cout << getSum(st, n, l, r) << " ";
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
 
    return 0;
}


Java
// java program for the above approach
import java.io.*;
import java.lang.*;
import java.util.*;
 
public class GFG {
 
    // Function to get the middle index
    // from the given ranges
    static int getMid(int s, int e)
    {
        return s + (e - s) / 2;
    }
 
    // Recursive function to find the sum
    // of values in the given range of
    // the array
    static int getSumUtil(int st[], int ss, int se, int qs,
                          int qe, int si)
    {
 
        // If segment of this node is a
        // part of given range, then
        // return the sum of the segment
        if (qs <= ss && qe >= se)
            return st[si];
 
        // If segment of this node is
        // outside the given range
        if (se < qs || ss > qe)
            return 0;
 
        // If a part of this segment
        // overlaps the given range
        int mid = getMid(ss, se);
 
        return getSumUtil(st, ss, mid, qs, qe, 2 * si + 1)
            + getSumUtil(st, mid + 1, se, qs, qe,
                         2 * si + 2);
    }
 
    // Function to find the sum of elements
    // in the range from index qs (query
    // start) to qe (query end)
    static int getSum(int st[], int n, int qs, int qe)
    {
        // Invalid ranges
        if (qs < 0 || qe > n - 1 || qs > qe) {
            System.out.println("Invalid Input");
            return -1;
        }
 
        return getSumUtil(st, 0, n - 1, qs, qe, 0);
    }
 
    // Recursive function to construct the
    // Segment Tree for array[ss..se]. si
    // is index of current node in tree st
    static int constructSTUtil(int arr[], int ss, int se,
                               int st[], int si)
    {
        // If there is one element
        // in the array
        if (ss == se) {
            st[si] = arr[ss];
            return arr[ss];
        }
 
        int mid = getMid(ss, se);
 
        // Recur for left and right
        // subtrees and store the sum
        // of values in this node
        st[si]
            = constructSTUtil(arr, ss, mid, st, si * 2 + 1)
              + constructSTUtil(arr, mid + 1, se, st,
                                si * 2 + 2);
        return st[si];
    }
 
    // Function to construct segment tree
    // from the given array
    static int[] constructST(int arr[], int n)
    {
        // Allocate memory for the segment
        // tree Height of segment tree
        int x = (int)(Math.ceil(Math.log(n) / Math.log(2)));
 
        // Maximum size of segment tree
        int max_size = 2 * (int)Math.pow(2, x) - 1;
 
        // Allocate memory
        int st[] = new int[max_size];
 
        // Fill the allocated memory st
        constructSTUtil(arr, 0, n - 1, st, 0);
 
        // Return the constructed
        // segment tree
        return st;
    }
 
    // Function to find the sum of elements
    // having odd number of divisors in
    // index range [L, R] for Q queries
    static void OddDivisorsSum(int n, int q, int arr[],
                               int Query[][])
    {
        // Traverse the array, arr[]
        for (int i = 0; i < n; i++) {
            int sq = (int)Math.sqrt(arr[i]);
 
            // Replace elements that are
            // not perfect squares with 0
            if (sq * sq != arr[i])
                arr[i] = 0;
        }
 
        // Build segment tree from the
        // given array
        int st[] = constructST(arr, n);
 
        // Iterate through all the queries
        for (int i = 0; i < q; i++) {
            int l = Query[i][0];
            int r = Query[i][1];
 
            // Print sum of values in
            // array from index l to r
            System.out.print(getSum(st, n, l, r) + " ");
        }
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        int arr[] = { 2, 4, 5, 6, 9 };
        int N = arr.length;
        int Q = 3;
        int Query[][] = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
        OddDivisorsSum(N, Q, arr, Query);
    }
}
 
// This code is contributed by Kingash.


C++
// C++ program for the above approach
 
#include 
using namespace std;
 
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int a[],
                    vector > Query)
{
    // Initialize the dp[] array
    int DP[n] = { 0 };
 
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int x = sqrt(a[i]);
 
        // If a[i] is a perfect square,
        // then update value of DP[i] to a[i]
        if (x * x == a[i])
            DP[i] = a[i];
    }
 
    // Find the prefix sum of DP[] array
    for (int i = 1; i < n; i++) {
        DP[i] = DP[i - 1] + DP[i];
    }
 
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
 
        int l = Query[i].first;
        int r = Query[i].second;
 
        // Find the sum for each query
        if (l == 0) {
            cout << DP[r] << " ";
        }
        else {
            cout << DP[r] - DP[l - 1]
                 << " ";
        }
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
 
    return 0;
}


Python3
# Python3 program for the above approach
from math import sqrt
 
# Function to find the sum of elements
# having odd number of divisors in
# index range [L, R] for Q queries
def OddDivisorsSum(n, q, a, Query):
   
    # Initialize the dp[] array
    DP = [0]*n
     
    # Traverse the array, arr[]
    for i in range(n):
        x = sqrt(a[i])
 
        # If a[i] is a perfect square,
        # then update value of DP[i] to a[i]
        if (x * x == a[i]):
            DP[i] = a[i]
 
    # Find the prefix sum of DP[] array
    for i in range(1, n):
        DP[i] = DP[i - 1] + DP[i]
 
    # Iterate through all the queries
    for i in range(q):
        l = Query[i][0]
        r = Query[i][1]
 
        # Find the sum for each query
        if (l == 0):
            print(DP[r], end=" ")
        else:
            print(DP[r] - DP[l - 1], end=" ")
 
# Driver Code
if __name__ == '__main__':
    arr = [2, 4, 5, 6, 9]
    N = len(arr)
    Q = 3
    Query = [ [ 0, 2 ], [ 1, 3 ], [ 1, 4 ] ]
    OddDivisorsSum(N, Q, arr, Query)
 
    # This code is contributed by mohit kumar 29.


C#
// C# program for the above approach
using System;
class GFG
{
   
    // Function to find the sum of elements
    // having odd number of divisors in
    // index range [L, R] for Q queries
    static void OddDivisorsSum(int n, int q, int[] a,
                               int[, ] Query)
    {
       
        // Initialize the dp[] array
        int[] DP = new int[n];
 
        // Traverse the array, arr[]
        for (int i = 0; i < n; i++) {
            int x = (int)(Math.Sqrt(a[i]));
 
            // If a[i] is a perfect square,
            // then update value of DP[i] to a[i]
            if (x * x == a[i])
                DP[i] = a[i];
        }
 
        // Find the prefix sum of DP[] array
        for (int i = 1; i < n; i++) {
            DP[i] = DP[i - 1] + DP[i];
        }
 
        // Iterate through all the queries
        for (int i = 0; i < q; i++) {
 
            int l = Query[i, 0];
            int r = Query[i, 1];
 
            // Find the sum for each query
            if (l == 0) {
                Console.Write(DP[r] + " ");
            }
            else {
                Console.Write(DP[r] - DP[l - 1] + " ");
            }
        }
    }
 
    // Driver Code
    public static void Main()
    {
        int[] arr = { 2, 4, 5, 6, 9 };
        int N = arr.Length;
        int Q = 3;
        int[, ] Query = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
        OddDivisorsSum(N, Q, arr, Query);
    }
}
 
// This code is contributed by ukasp.


输出:
4 4 13

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

高效的方法:为了优化上述方法,想法是使用一个辅助数组来存储具有奇数个除数的元素的前缀和。请按照以下步骤解决问题:

  • 0初始化大小为N的数组dp[]
  • 使用变量i遍历给定的数组arr[]并检查是否有任何元素是完美正方形。如果发现为真,则将dp[i]的值更新为arr[i]
  • 查找数组dp[]的前缀和。
  • 遍历所有查询,对于[L, R]范围内的每个查询,答案将由(dp[R] – dp[L – 1]) 给出

下面是上述方法的实现:

C++

// C++ program for the above approach
 
#include 
using namespace std;
 
// Function to find the sum of elements
// having odd number of divisors in
// index range [L, R] for Q queries
void OddDivisorsSum(int n, int q, int a[],
                    vector > Query)
{
    // Initialize the dp[] array
    int DP[n] = { 0 };
 
    // Traverse the array, arr[]
    for (int i = 0; i < n; i++) {
        int x = sqrt(a[i]);
 
        // If a[i] is a perfect square,
        // then update value of DP[i] to a[i]
        if (x * x == a[i])
            DP[i] = a[i];
    }
 
    // Find the prefix sum of DP[] array
    for (int i = 1; i < n; i++) {
        DP[i] = DP[i - 1] + DP[i];
    }
 
    // Iterate through all the queries
    for (int i = 0; i < q; i++) {
 
        int l = Query[i].first;
        int r = Query[i].second;
 
        // Find the sum for each query
        if (l == 0) {
            cout << DP[r] << " ";
        }
        else {
            cout << DP[r] - DP[l - 1]
                 << " ";
        }
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 2, 4, 5, 6, 9 };
    int N = sizeof(arr) / sizeof(arr[0]);
    int Q = 3;
    vector > Query
        = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
    OddDivisorsSum(N, Q, arr, Query);
 
    return 0;
}

蟒蛇3

# Python3 program for the above approach
from math import sqrt
 
# Function to find the sum of elements
# having odd number of divisors in
# index range [L, R] for Q queries
def OddDivisorsSum(n, q, a, Query):
   
    # Initialize the dp[] array
    DP = [0]*n
     
    # Traverse the array, arr[]
    for i in range(n):
        x = sqrt(a[i])
 
        # If a[i] is a perfect square,
        # then update value of DP[i] to a[i]
        if (x * x == a[i]):
            DP[i] = a[i]
 
    # Find the prefix sum of DP[] array
    for i in range(1, n):
        DP[i] = DP[i - 1] + DP[i]
 
    # Iterate through all the queries
    for i in range(q):
        l = Query[i][0]
        r = Query[i][1]
 
        # Find the sum for each query
        if (l == 0):
            print(DP[r], end=" ")
        else:
            print(DP[r] - DP[l - 1], end=" ")
 
# Driver Code
if __name__ == '__main__':
    arr = [2, 4, 5, 6, 9]
    N = len(arr)
    Q = 3
    Query = [ [ 0, 2 ], [ 1, 3 ], [ 1, 4 ] ]
    OddDivisorsSum(N, Q, arr, Query)
 
    # This code is contributed by mohit kumar 29.

C#

// C# program for the above approach
using System;
class GFG
{
   
    // Function to find the sum of elements
    // having odd number of divisors in
    // index range [L, R] for Q queries
    static void OddDivisorsSum(int n, int q, int[] a,
                               int[, ] Query)
    {
       
        // Initialize the dp[] array
        int[] DP = new int[n];
 
        // Traverse the array, arr[]
        for (int i = 0; i < n; i++) {
            int x = (int)(Math.Sqrt(a[i]));
 
            // If a[i] is a perfect square,
            // then update value of DP[i] to a[i]
            if (x * x == a[i])
                DP[i] = a[i];
        }
 
        // Find the prefix sum of DP[] array
        for (int i = 1; i < n; i++) {
            DP[i] = DP[i - 1] + DP[i];
        }
 
        // Iterate through all the queries
        for (int i = 0; i < q; i++) {
 
            int l = Query[i, 0];
            int r = Query[i, 1];
 
            // Find the sum for each query
            if (l == 0) {
                Console.Write(DP[r] + " ");
            }
            else {
                Console.Write(DP[r] - DP[l - 1] + " ");
            }
        }
    }
 
    // Driver Code
    public static void Main()
    {
        int[] arr = { 2, 4, 5, 6, 9 };
        int N = arr.Length;
        int Q = 3;
        int[, ] Query = { { 0, 2 }, { 1, 3 }, { 1, 4 } };
        OddDivisorsSum(N, Q, arr, Query);
    }
}
 
// This code is contributed by ukasp.
输出:
4 4 13

时间复杂度: O(N)
辅助空间: O(N)

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live