Number of ways to change the Array such that largest element is LCM of array

Given an array

arr[]

, the task is to count the number of the unique arrays can be formed by updating the elements of the given array to any element in the range [1, arr[i]] such that the

of the updated array is equal to the maximum element.

Examples:

Input: arr[] = {6, 3} Output: 13 Explanation: Possible Arrays are – {[1, 1], [1, 2], [2, 1], [2, 2], [1, 3], [3, 1], [3, 3], [4, 1], [4, 2], [5, 1], [6, 1], [6, 2], [6, 3]} Input: arr[] = {1, 4, 3, 2} Output: 15

Approach:

  • For the maximum element to be the LCM of the array, we need to fix the maximum element of the array.
  • As, we have fixed some number as maximum, now for the LCM to be , we’ll need to ensure that every element in the array is some multiple of including
  • We’ll find the factors for the number and find the number of ways to place them in the array.
  • Let’s say that the factors of be . The count of factors is .
  • Let’s assume that number of positions that be means there are number of positions that have number in the array which is greater than equal to and let have positions and have positions.
  • Now, number of ways to distribute x in positions, in positions and in positions are and so on.
  • Now, we’ll have to subtract those ways which have LCM but is not there.
  • We’ll need to subtract from the ways.
  • We’ll use BIT(Binary Indexed Tree) to find number of positions greater than some number .

Below is the implementation of the above approach:

C++

// C++ implementation to find the
// Number of ways to change the array
// such that maximum element of the
// array is the LCM of the array
 
#include <bits/stdc++.h>
using namespace std;
 
// Modulo
const int MOD = 1e9 + 7;
const int N = 1e5 + 5;
 
// Fenwick tree to find number
// of indexes greater than x
vector<int> BIT(N, 0);
 
// Function to compute
// x ^ y % MOD
int power(int x, int y)
{
    if (x == 0)
        return 0;
 
    int ans = 1;
 
    // Loop to compute the
    // x^y % MOD
    while (y > 0) {
        if (y & 1)
            ans = (1LL * ans * x) % MOD;
 
        x = (1LL * x * x) % MOD;
        y >>= 1;
    }
    return ans;
}
 
// Function to update the binary
// indexed tree
void updateBIT(int idx, int val)
{
    assert(idx > 0);
    while (idx < N) {
        BIT[idx] += val;
        idx += idx & -idx;
    }
}
 
// Function to find the prefix sum
// upto the current index
int queryBIT(int idx)
{
    int ans = 0;
    while (idx > 0) {
        ans += BIT[idx];
        idx -= idx & -idx;
    }
    return ans;
}
 
// Function to find the number of
// ways to change the array such
// that the LCM of array is
// maximum element of the array
int numWays(int arr[], int n)
{
 
    int mx = 0;
    for (int i = 0; i < n; i++) {
 
        // Updating BIT with the
        // frequency of elements
        updateBIT(arr[i], 1);
 
        // Maximum element in the array
        mx = max(mx, arr[i]);
    }
 
    // 1 is for every element
    // is 1 in the array;
    int ans = 1;
    for (int i = 2; i <= mx; i++) {
 
        // Vector for storing the factors
        vector<int> factors;
        for (int j = 1; j * j <= i; j++) {
 
            // finding factors of i
            if (i % j == 0) {
                factors.push_back(j);
                if (i / j != j)
                    factors.push_back(i / j);
            }
        }
        // Sorting in descending order
        sort(factors.rbegin(), factors.rend());
 
        int cnt = 1;
 
        // for storing number of indexex
        // greater than the i - 1 element
        int prev = 0;
        for (int j = 0; j < factors.size(); j++) {
 
            // Number of remaining factors
            int remFactors = int(factors.size()) - j;
 
            // Number of indexes in the array
            // with element factor[j] and above
            int indexes = n - queryBIT(factors[j] - 1);
 
            // Multiplying count with
            // remFcators ^ (indexes - prev)
            cnt = (1LL
                   * cnt
                   * power(remFactors,
                           indexes - prev))
                  % MOD;
            prev = max(prev, indexes);
        }
 
        // Remove those counts which have
        // lcm as i but i is not present
        factors.erase(factors.begin());
 
        int toSubtract = 1;
        prev = 0;
 
        // Loop to find the count which have
        // lcm as i  but i is not present
        for (int j = 0; j < factors.size(); j++) {
            int remFactors = int(factors.size()) - j;
            int indexes = n - queryBIT(factors[j] - 1);
 
            toSubtract = (1LL
                          * toSubtract
                          * power(remFactors,
                                  indexes - prev));
            prev = max(prev, indexes);
        }
 
        // Adding cnt - toSubtract to answer
        ans = (1LL * ans + cnt
               - toSubtract + MOD)
              % MOD;
    }
    return ans;
}
 
// Driver Code
int main()
{
    int arr[] = { 6, 3 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    int ans = numWays(arr, n);
    cout << ans << endl;
    return 0;
}

                    

Java

import java.util.*;
 
public class Main {
 
    // Modulo
    static final int MOD = 1000000007;
    static final int N = 100005;
 
    // Fenwick tree to find number
    // of indexes greater than x
    static List<Integer> BIT
        = new ArrayList<>(Collections.nCopies(N, 0));
 
    // Function to compute
    // x ^ y % MOD
    static int power(int x, int y)
    {
        if (x == 0)
            return 0;
 
        int ans = 1;
 
        // Loop to compute the
        // x^y % MOD
        while (y > 0) {
            if ((y & 1) != 0)
                ans = (int)((1L * ans * x) % MOD);
 
            x = (int)((1L * x * x) % MOD);
            y >>= 1;
        }
        return ans;
    }
 
    // Function to update the binary
    // indexed tree
    static void updateBIT(int idx, int val)
    {
        assert idx > 0;
        while (idx < N) {
            BIT.set(idx, BIT.get(idx) + val);
            idx += idx & -idx;
        }
    }
 
    // Function to find the prefix sum
    // upto the current index
    static int queryBIT(int idx)
    {
        int ans = 0;
        while (idx > 0) {
            ans += BIT.get(idx);
            idx -= idx & -idx;
        }
        return ans;
    }
 
    // Function to find the number of
    // ways to change the array such
    // that the LCM of array is
    // maximum element of the array
    static int numWays(int[] arr, int n)
    {
 
        int mx = 0;
        for (int i = 0; i < n; i++) {
 
            // Updating BIT with the
            // frequency of elements
            updateBIT(arr[i], 1);
 
            // Maximum element in the array
            mx = Math.max(mx, arr[i]);
        }
 
        // 1 is for every element
        // is 1 in the array;
        int ans = 1;
        for (int i = 2; i <= mx; i++) {
 
            // Vector for storing the factors
            List<Integer> factors = new ArrayList<>();
            for (int j = 1; j * j <= i; j++) {
 
                // finding factors of i
                if (i % j == 0) {
                    factors.add(j);
                    if (i / j != j)
                        factors.add(i / j);
                }
            }
            // Sorting in descending order
            factors.sort(Collections.reverseOrder());
 
            int cnt = 1;
 
            // for storing number of indexex
            // greater than the i - 1 element
            int prev = 0;
            for (int j = 0; j < factors.size(); j++) {
 
                // Number of remaining factors
                int remFactors = factors.size() - j;
 
                // Number of indexes in the array
                // with element factor[j] and above
                int indexes
                    = n - queryBIT(factors.get(j) - 1);
 
                // Multiplying count with
                // remFcators ^ (indexes - prev)
                cnt = (int)((1L * cnt
                             * power(remFactors,
                                     indexes - prev))
                            % MOD);
                prev = Math.max(prev, indexes);
            }
 
            // Remove those counts which have
            // lcm as i but i is not present
            factors.remove(0);
 
            int toSubtract = 1;
            prev = 0;
 
            // Loop to find the count which have
            // lcm as i but i is not present
            for (int j = 0; j < factors.size(); j++) {
                int remFactors = factors.size() - j;
                int indexes
                    = n - queryBIT(factors.get(j) - 1);
 
                toSubtract = (int)((1L * toSubtract
                                    * power(remFactors,
                                            indexes - prev))
                                   % MOD);
                prev = Math.max(prev, indexes);
            }
 
            // Adding cnt - toSubtract to answer
            ans = (int)((1L * ans + cnt - toSubtract + MOD)
                        % MOD);
        }
        return ans;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
        int[] arr = { 6, 3 };
        int n = arr.length;
 
        int ans = numWays(arr, n);
        System.out.println(ans);
    }
}
 
// This code is contributed by Samim Hossain Mondal.

                    

Python3

# Python implementation to find the
# Number of ways to change the array
# such that maximum element of the
# array is the LCM of the array
 
# Modulo
MOD = int(1e9) + 9
MAXN = int(1e5) + 5
 
# Fenwick tree to find number
# of indexes greater than x
BIT = [0 for _ in range(MAXN)]
 
# Function to compute
# x ^ y % MOD
def power(x, y):
    if x == 0:
        return 0
    ans = 1
     
    # Loop to compute the
    # x ^ y % MOD
    while y > 0:
        if y % 2 == 1:
            ans = (ans * x) % MOD
        x = (x * x) % MOD
        y = y // 2
    return ans
 
# Function to update the
# Binary Indexed Tree
def updateBIT(idx, val):
     
    # Loop to update the BIT
    while idx < MAXN:
        BIT[idx] += val
        idx += idx & (-idx)
 
# Function to find
# prefix sum upto idx
def queryBIT(idx):
    ans = 0
    while idx > 0:
        ans += BIT[idx]
        idx -= idx & (-idx)
    return ans
 
# Function to find number of ways
# to change the array such that
# MAX of array is same as LCM
def numWays(arr):
    mx = 0
     
    # Updating BIT with the
    # frequency of elements
    for i in arr:
        updateBIT(i, 1)
         
        # Maximum element
        # in the array
        mx = max(mx, i)
 
    ans = 1
    for i in range(2, mx + 1):
         
        # For storing factors of i
        factors = []
        for j in range(1, i + 1):
            if j * j > i:
                break
                 
            # Finding factors of i
            if i % j == 0:
                factors.append(j)
                if i // j != j:
                    factors.append(i // j)
 
        # Sorting in descending order
        factors.sort()
        factors.reverse()
         
        # For storing ans
        cnt = 1
         
        # For storing number of indexes
        # greater than the i - 1 element
        prev = 0
        for j in range(len(factors)):
             
            # Number of remaining factors
            remFactors = len(factors) - j
             
            # Number of indexes in the array
            # with element factor[j] and above
            indexes = len(arr) - queryBIT(factors[j] - 1)
             
            # Multiplying count with
            # remFcators ^ (indexes - prev)
            cnt = (cnt * power(remFactors, \
                     indexes - prev)) % MOD
            prev = max(prev, indexes)
 
        # Remove those counts which have
        # lcm as i but i is not present
        factors.remove(factors[0])
 
        toSubtract = 1
        prev = 0
        for j in range(len(factors)):
            remFactors = len(factors) - j
            indexes = len(arr) - queryBIT(factors[j] - 1)
 
            toSubtract = (toSubtract *\
              power(remFactors, indexes - prev))
            prev = max(prev, indexes)
 
        # Adding cnt - toSubtract to ans;
        ans = (ans + cnt - toSubtract + MOD) % MOD;
         
    return ans
 
# Driver Code
if __name__ == "__main__":
    arr = [1, 4, 3, 2]
     
    ans = numWays(arr);
    print(ans)

                    

C#

using System;
using System.Collections.Generic;
 
class MainClass {
    // Modulo
    const int MOD = 1000000007;
    const int N = 100005;
 
    // Fenwick tree to find the number
    // of indexes greater than x
    static List<int> BIT = new List<int>(new int[N]);
 
    // Function to compute x ^ y % MOD
    static int Power(int x, int y) {
        if (x == 0)
            return 0;
 
        int ans = 1;
 
        // Loop to compute x^y % MOD
        while (y > 0) {
            if ((y & 1) == 1)
                ans = (int)((1L * ans * x) % MOD);
 
            x = (int)((1L * x * x) % MOD);
            y >>= 1;
        }
        return ans;
    }
 
    // Function to update the binary
    // indexed tree
    static void UpdateBIT(int idx, int val) {
        if (idx <= 0)
            return;
 
        while (idx < N) {
            BIT[idx] += val;
            idx += idx & -idx;
        }
    }
 
    // Function to find the prefix sum
    // up to the current index
    static int QueryBIT(int idx) {
        int ans = 0;
        while (idx > 0) {
            ans += BIT[idx];
            idx -= idx & -idx;
        }
        return ans;
    }
 
    // Function to find the number of
    // ways to change the array such
    // that the LCM of the array is
    // the maximum element of the array
    static int NumWays(int[] arr, int n) {
        int mx = 0;
        for (int i = 0; i < n; i++) {
            // Updating BIT with the frequency of elements
            UpdateBIT(arr[i], 1);
            // Maximum element in the array
            mx = Math.Max(mx, arr[i]);
        }
 
        // 1 is for every element is 1 in the array;
        int ans = 1;
        for (int i = 2; i <= mx; i++) {
            // List for storing the factors
            List<int> factors = new List<int>();
            for (int j = 1; j * j <= i; j++) {
                // Finding factors of i
                if (i % j == 0) {
                    factors.Add(j);
                    if (i / j != j)
                        factors.Add(i / j);
                }
            }
            // Sorting in descending order
            factors.Sort((a, b) => b.CompareTo(a));
 
            int cnt = 1;
            // For storing the number of indexes greater than the i - 1 element
            int prev = 0;
 
            for (int j = 0; j < factors.Count; j++) {
                // Number of remaining factors
                int remFactors = factors.Count - j;
                // Number of indexes in the array with element factor[j] and above
                int indexes = n - QueryBIT(factors[j] - 1);
                // Multiplying count with remFcators ^ (indexes - prev)
                cnt = (int)(
                  (1L * cnt * Power(remFactors, indexes - prev)) % MOD);
                prev = Math.Max(prev, indexes);
            }
 
            // Remove those counts which have lcm as i but i is not present
            factors.RemoveAt(0);
            int toSubtract = 1;
            prev = 0;
 
            // Loop to find the count which has lcm as i but i is not present
            for (int j = 0; j < factors.Count; j++) {
                int remFactors = factors.Count - j;
                int indexes = n - QueryBIT(factors[j] - 1);
                toSubtract = (int)(
                  (1L * toSubtract * Power(remFactors, indexes - prev)) % MOD);
                prev = Math.Max(prev, indexes);
            }
 
            // Adding cnt - toSubtract to the answer
            ans = (int)((1L * ans + cnt - toSubtract + MOD) % MOD);
        }
        return ans;
    }
 
    public static void Main(string[] args) {
        int[] arr = { 6, 3 };
        int n = arr.Length;
        int ans = NumWays(arr, n);
        Console.WriteLine(ans);
    }
}

                    

Javascript

// Modulo
const MOD = 1e9 + 7;
const N = 1e5 + 5;
// Fenwick tree to find the number of indexes greater than x
const BIT = new Array(N).fill(0);
// Function to compute x^y % MOD
function power(x, y) {
    if (x === 0) return 0;
    let ans = 1;
    // Loop to compute x^y % MOD
    while (y > 0) {
        if (y & 1) ans = (ans * x) % MOD;
 
        x = (x * x) % MOD;
        y >>= 1;
    }
    return ans;
}
// Function to update the binary indexed tree
function updateBIT(idx, val) {
    while (idx > 0) {
        BIT[idx] += val;
        idx += idx & -idx;
    }
}
// Function to find the prefix sum up to
// the current index
function queryBIT(idx) {
    let ans = 0;
    while (idx > 0) {
        ans += BIT[idx];
        idx -= idx & -idx;
    }
    return ans;
}
function GFG(arr, n) {
    let mx = 0;
    for (let i = 0; i < n; i++) {
        // Updating BIT with the frequency of elements
        updateBIT(arr[i], 1);
        // Maximum element in the array
        mx = Math.max(mx, arr[i]);
    }
    // 1 is for every element is 1 in the array
    let ans = 1;
    for (let i = 2; i <= mx; i++) {
        // Vector for storing the factors
        const factors = [];
        for (let j = 1; j * j <= i; j++) {
            // Finding factors of i
            if (i % j === 0) {
                factors.push(j);
                if (i / j !== j) factors.push(i / j);
            }
        }
        // Sorting in descending order
        factors.sort((a, b) => b - a);
        let cnt = 1;
        // For storing the number of indexes greater than
        // the (i - 1) element
        let prev = 0;
        for (let j = 0; j < factors.length; j++) {
            // Number of remaining factors
            const remFactors = factors.length - j;
            // Number of indexes in the array with an element >= factor[j]
            const indexes = n - queryBIT(factors[j] - 1);
            // Multiplying count with (remFactors ^ (indexes - prev))
            cnt = (cnt * power(remFactors, indexes - prev)) % MOD;
            prev = Math.max(prev, indexes);
        }
        // Remove those counts which have LCM as i but i is not present
        factors.shift();
        let toSubtract = 1;
        prev = 0;
        // Loop to find the count which have LCM as i but i is not present
        for (let j = 0; j < factors.length; j++) {
            const remFactors = factors.length - j;
            const indexes = n - queryBIT(factors[j] - 1);
            toSubtract = (toSubtract * power(remFactors, indexes - prev)) % MOD
            prev = Math.max(prev, indexes);
        }
        // Adding cnt - toSubtract to answer
        ans = (ans + cnt - toSubtract + MOD) % MOD;
    }
    return ans;
}
// Driver Code
const arr = [6, 3];
const n = arr.length;
const ans = GFG(arr, n);
console.log(ans);

                    

Output
13








Time Complexity:

, where

is the maximum element in the array.