给定一个整数K和一个数组arr [] ,任务是计算乘积可被K整除的所有子数组。
例子:
Input: arr[] = {6, 2, 8}, K = 4
Output: 4
Required sub-arrays are {6, 2}, {6, 2, 8}, {2, 8}and {8}.
Input: arr[] = {9, 1, 14}, K = 6
Output: 1
天真的方法:运行嵌套循环并检查每个子数组乘积%k == 0 。当子数组的条件为true时,更新计数=计数+ 1 。该方法的时间复杂度为O(n 3 ) 。
C++
// C++ implementation of the approach
#include
using namespace std;
#define ll long long
// Function to count sub-arrays whose
// product is divisible by K
int countSubarrays(const int* arr, int n, int K)
{
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// Calculate the product of the
// current sub-array
ll product = 1;
for (int x = i; x <= j; x++)
product *= arr[x];
// If product of the current sub-array
// is divisible by K
if (product % K == 0)
count++;
}
}
return count;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int K = 4;
cout << countSubarrays(arr, n, K);
return 0;
}
Java
// Java implementation of the approach
import java.util.*;
class GFG
{
// Function to count sub-arrays whose
// product is divisible by K
static int countSubarrays(int []arr, int n, int K)
{
int count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Calculate the product of the
// current sub-array
long product = 1;
for (int x = i; x <= j; x++)
product *= arr[x];
// If product of the current sub-array
// is divisible by K
if (product % K == 0)
count++;
}
}
return count;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 6, 2, 8 };
int n = arr.length;
int K = 4;
System.out.println(countSubarrays(arr, n, K));
}
}
// This code contributed by Rajput-Ji
Python 3
# Python 3 implementation of the approach
# Function to count sub-arrays whose
# product is divisible by K
def countSubarrays(arr, n, K):
count = 0
for i in range( n):
for j in range(i, n):
# Calculate the product of
# the current sub-array
product = 1
for x in range(i, j + 1):
product *= arr[x]
# If product of the current
# sub-array is divisible by K
if (product % K == 0):
count += 1
return count
# Driver code
if __name__ == "__main__":
arr = [ 6, 2, 8 ]
n = len(arr)
K = 4
print(countSubarrays(arr, n, K))
# This code is contributed by ita_c
C#
// C# implementation of the approach
using System;
class GFG
{
// Function to count sub-arrays whose
// product is divisible by K
static int countSubarrays(int []arr, int n, int K)
{
int count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Calculate the product of the
// current sub-array
long product = 1;
for (int x = i; x <= j; x++)
product *= arr[x];
// If product of the current sub-array
// is divisible by K
if (product % K == 0)
count++;
}
}
return count;
}
// Driver code
public static void Main()
{
int []arr = { 6, 2, 8 };
int n = arr.Length;
int K = 4;
Console.WriteLine(countSubarrays(arr, n, K));
}
}
// This code contributed by Rajput-Ji
PHP
Javascript
C++
// C++ implementation of the approach
#include
using namespace std;
#define ll long long
#define MAX 100002
// Segment tree implemented as an array
ll tree[4 * MAX];
// Function to build the segment tree
void build(int node, int start, int end, const int* arr, int k)
{
if (start == end) {
tree[node] = (1LL * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
ll query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l) {
return 1;
}
if (start >= l && end <= r) {
return tree[node] % k;
}
int mid = (start + end) >> 1;
ll q1 = query(2 * node, start, mid, l, r, k);
ll q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
ll countSubarrays(const int* arr, int n, int k)
{
ll count = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// Query segment tree to find product % k
// of the sub-array[i..j]
ll product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0) {
count++;
}
}
}
return count;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
cout << countSubarrays(arr, n, k);
return 0;
}
Java
// Java implementation for above approach
class GFG
{
static int MAX = 100002;
// Segment tree implemented as an array
static long tree[] = new long[4 * MAX];
// Function to build the segment tree
static void build(int node, int start, int end,
int []arr, int k)
{
if (start == end)
{
tree[node] = (1L * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
static long query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
{
return 1;
}
if (start >= l && end <= r)
{
return tree[node] % k;
}
int mid = (start + end) >> 1;
long q1 = query(2 * node, start, mid, l, r, k);
long q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
static long countSubarrays(int []arr, int n, int k)
{
long count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Query segment tree to find product % k
// of the sub-array[i..j]
long product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0)
{
count++;
}
}
}
return count;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 6, 2, 8 };
int n = arr.length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
System.out.println(countSubarrays(arr, n, k));
}
}
// This code has been contributed by 29AjayKumar
Python3
# Python3 implementation of the approach
MAX = 100002
# Segment tree implemented as an array
tree = [0 for i in range(4 * MAX)];
# Function to build the segment tree
def build(node, start, end, arr, k):
if (start == end):
tree[node] = (arr[start]) % k;
return;
mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
# Function to query product of
# sub-array[l..r] in O(log n) time
def query(node, start, end, l, r, k):
if (start > end or start > r or end < l):
return 1;
if (start >= l and end <= r):
return tree[node] % k;
mid = (start + end) >> 1;
q1 = query(2 * node, start, mid, l, r, k);
q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
# Function to count sub-arrays whose
# product is divisible by K
def countSubarrays(arr, n, k):
count = 0;
for i in range(n):
for j in range(i, n):
# Query segment tree to find product % k
# of the sub-array[i..j]
product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0):
count += 1
return count;
# Driver code
if __name__=='__main__':
arr = [ 6, 2, 8 ]
n = len(arr)
k = 4;
# Build the segment tree
build(1, 0, n - 1, arr, k);
print(countSubarrays(arr, n, k))
# This code is contributed by pratham76.
C#
// C# implementation for above approach
using System;
class GFG
{
static int MAX = 100002;
// Segment tree implemented as an array
static long []tree = new long[4 * MAX];
// Function to build the segment tree
static void build(int node, int start, int end,
int []arr, int k)
{
if (start == end)
{
tree[node] = (1L * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
static long query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
{
return 1;
}
if (start >= l && end <= r)
{
return tree[node] % k;
}
int mid = (start + end) >> 1;
long q1 = query(2 * node, start, mid, l, r, k);
long q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
static long countSubarrays(int []arr, int n, int k)
{
long count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Query segment tree to find product % k
// of the sub-array[i..j]
long product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0)
{
count++;
}
}
}
return count;
}
// Driver code
public static void Main(String[] args)
{
int []arr = { 6, 2, 8 };
int n = arr.Length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
Console.WriteLine(countSubarrays(arr, n, k));
}
}
/* This code contributed by PrinciRaj1992 */
CPP
// C++ implementation of the approach
#include
using namespace std;
#define MAX 100005
typedef long long ll;
// Segment tree implemented as an array
ll tree[MAX << 2];
// Function to build segment tree
void build(int node, int start, int end, const int* arr, int k)
{
if (start == end) {
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
ll query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
ll q1 = query(2 * node, start, mid, l, r, k);
ll q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
ll countSubarrays(int* arr, int n, int k)
{
ll ans = 0;
for (int i = 0; i < n; i++) {
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high) {
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
cout << countSubarrays(arr, n, k);
return 0;
}
Java
// Java implementation of the approach
class GFG
{
static int MAX = 100005;
// Segment tree implemented as an array
static int tree[] = new int[MAX << 2];
// Function to build segment tree
static void build(int node, int start,
int end, int arr[], int k)
{
if (start == end) {
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
static int query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
int q1 = query(2 * node, start, mid, l, r, k);
int q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
static int countSubarrays(int arr[], int n, int k)
{
int ans = 0;
for (int i = 0; i < n; i++)
{
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high)
{
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 6, 2, 8 };
int n = arr.length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
System.out.println(countSubarrays(arr, n, k));
}
}
// This code is contributed by divyesh072019
Python3
# Python3 implementation of the approach
MAX = 100005
# Segment tree implemented as an array
tree = [0 for i in range(MAX << 2)];
# Function to build segment tree
def build(node, start, end, arr, k):
if (start == end):
tree[node] = arr[start] % k;
return;
mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
# Function to query product % k
# of sub-array[l..r]
def query(node, start, end, l, r, k):
if (start > end or start > r or end < l):
return 1;
if (start >= l and end <= r):
return tree[node] % k;
mid = (start + end) >> 1;
q1 = query(2 * node, start, mid, l, r, k);
q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
# Function to return the count of sub-arrays
# whose product is divisible by K
def countSubarrays(arr, n, k):
ans = 0;
for i in range(n):
low = i
high = n - 1;
# Binary search
# Check if sub-array[i..mid] satisfies the constraint
# Adjust low and high accordingly
while (low <= high):
mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0):
high = mid - 1;
else:
low = mid + 1;
ans += n - low;
return ans;
# Driver code
if __name__=='__main__':
arr = [ 6, 2, 8 ]
n = len(arr)
k = 4;
# Build the segment tree
build(1, 0, n - 1, arr, k);
print(countSubarrays(arr, n, k))
# This code is contributed by rutvik_56.
C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
class GFG
{
static int MAX = 100005;
// Segment tree implemented as an array
static int[] tree = new int[MAX << 2];
// Function to build segment tree
static void build(int node, int start,
int end, int[] arr, int k)
{
if (start == end)
{
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
static int query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
int q1 = query(2 * node, start, mid, l, r, k);
int q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
static int countSubarrays(int[] arr, int n, int k)
{
int ans = 0;
for (int i = 0; i < n; i++)
{
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high)
{
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
static void Main() {
int[] arr = { 6, 2, 8 };
int n = arr.Length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
Console.Write(countSubarrays(arr, n, k));
}
}
// This code is contributed by divyeshrbadiya07
CPP
// C++ implementation of the approach
#include
using namespace std;
#define ll long long
#define MAX 100002
#define pb push_back
// Vector to store primes
vector primes;
// k_cnt stores count of prime factors of k
// current_map stores the count of primes
// in the current sub-array
// cnts[] is an array of maps which stores
// the count of primes for element at index i
unordered_map k_cnt, current_map, cnts[MAX];
// Function to store primes in
// the vector primes
void sieve()
{
int prime[MAX];
prime[0] = prime[1] = 1;
for (int i = 2; i < MAX; i++) {
if (prime[i] == 0) {
for (int j = i * 2; j < MAX; j += i) {
if (prime[j] == 0) {
prime[j] = i;
}
}
}
}
for (int i = 2; i < MAX; i++) {
if (prime[i] == 0) {
prime[i] = i;
primes.pb(i);
}
}
}
// Function to count sub-arrays whose product
// is divisible by k
ll countSubarrays(int* arr, int n, int k)
{
// Special case
if (k == 1) {
cout << (1LL * n * (n + 1)) / 2;
return 0;
}
vector k_primes;
for (auto p : primes) {
while (k % p == 0) {
k_primes.pb(p);
k /= p;
}
}
// If k is prime and is more than 10^6
if (k > 1) {
k_primes.pb(k);
}
for (auto num : k_primes) {
k_cnt[num]++;
}
// Two pointers initialized
int l = 0, r = 0;
ll ans = 0;
while (r < n) {
// Add rth element to the current segment
for (auto& it : k_cnt) {
// p = prime factor of k
int p = it.first;
while (arr[r] % p == 0) {
current_map[p]++;
cnts[r][p]++;
arr[r] /= p;
}
}
// Check if current sub-array's product
// is divisible by k
int flag = 0;
for (auto& it : k_cnt) {
int p = it.first;
if (current_map[p] < k_cnt[p]) {
flag = 1;
break;
}
}
// If for all prime factors p of k,
// current_map[p] >= k_cnt[p]
// then current sub-array is divisible by k
if (!flag) {
// flag = 0 means that after adding rth element
// segment's product is divisible by k
ans += n - r;
// Eliminate 'l' from the current segment
for (auto& it : k_cnt) {
int p = it.first;
current_map[p] -= cnts[l][p];
}
l++;
}
else {
r++;
}
}
return ans;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
sieve();
cout << countSubarrays(arr, n, k);
return 0;
}
4
更好的方法是使用双指针技术或使用段树来快速找到子数组的乘积。
细分树:天真的解决方案的复杂性是三次的。这是因为遍历了每个子数组以找到乘积。无需遍历每个子数组,而是可以将乘积存储在段树中,并且可以查询树以获取O(log n)时间的乘积%k值。因此,该方法的时间复杂度将为O(n 2 log n) 。
C++
// C++ implementation of the approach
#include
using namespace std;
#define ll long long
#define MAX 100002
// Segment tree implemented as an array
ll tree[4 * MAX];
// Function to build the segment tree
void build(int node, int start, int end, const int* arr, int k)
{
if (start == end) {
tree[node] = (1LL * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
ll query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l) {
return 1;
}
if (start >= l && end <= r) {
return tree[node] % k;
}
int mid = (start + end) >> 1;
ll q1 = query(2 * node, start, mid, l, r, k);
ll q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
ll countSubarrays(const int* arr, int n, int k)
{
ll count = 0;
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// Query segment tree to find product % k
// of the sub-array[i..j]
ll product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0) {
count++;
}
}
}
return count;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
cout << countSubarrays(arr, n, k);
return 0;
}
Java
// Java implementation for above approach
class GFG
{
static int MAX = 100002;
// Segment tree implemented as an array
static long tree[] = new long[4 * MAX];
// Function to build the segment tree
static void build(int node, int start, int end,
int []arr, int k)
{
if (start == end)
{
tree[node] = (1L * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
static long query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
{
return 1;
}
if (start >= l && end <= r)
{
return tree[node] % k;
}
int mid = (start + end) >> 1;
long q1 = query(2 * node, start, mid, l, r, k);
long q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
static long countSubarrays(int []arr, int n, int k)
{
long count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Query segment tree to find product % k
// of the sub-array[i..j]
long product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0)
{
count++;
}
}
}
return count;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 6, 2, 8 };
int n = arr.length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
System.out.println(countSubarrays(arr, n, k));
}
}
// This code has been contributed by 29AjayKumar
Python3
# Python3 implementation of the approach
MAX = 100002
# Segment tree implemented as an array
tree = [0 for i in range(4 * MAX)];
# Function to build the segment tree
def build(node, start, end, arr, k):
if (start == end):
tree[node] = (arr[start]) % k;
return;
mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
# Function to query product of
# sub-array[l..r] in O(log n) time
def query(node, start, end, l, r, k):
if (start > end or start > r or end < l):
return 1;
if (start >= l and end <= r):
return tree[node] % k;
mid = (start + end) >> 1;
q1 = query(2 * node, start, mid, l, r, k);
q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
# Function to count sub-arrays whose
# product is divisible by K
def countSubarrays(arr, n, k):
count = 0;
for i in range(n):
for j in range(i, n):
# Query segment tree to find product % k
# of the sub-array[i..j]
product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0):
count += 1
return count;
# Driver code
if __name__=='__main__':
arr = [ 6, 2, 8 ]
n = len(arr)
k = 4;
# Build the segment tree
build(1, 0, n - 1, arr, k);
print(countSubarrays(arr, n, k))
# This code is contributed by pratham76.
C#
// C# implementation for above approach
using System;
class GFG
{
static int MAX = 100002;
// Segment tree implemented as an array
static long []tree = new long[4 * MAX];
// Function to build the segment tree
static void build(int node, int start, int end,
int []arr, int k)
{
if (start == end)
{
tree[node] = (1L * arr[start]) % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product of
// sub-array[l..r] in O(log n) time
static long query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
{
return 1;
}
if (start >= l && end <= r)
{
return tree[node] % k;
}
int mid = (start + end) >> 1;
long q1 = query(2 * node, start, mid, l, r, k);
long q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to count sub-arrays whose
// product is divisible by K
static long countSubarrays(int []arr, int n, int k)
{
long count = 0;
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
{
// Query segment tree to find product % k
// of the sub-array[i..j]
long product_mod_k = query(1, 0, n - 1, i, j, k);
if (product_mod_k == 0)
{
count++;
}
}
}
return count;
}
// Driver code
public static void Main(String[] args)
{
int []arr = { 6, 2, 8 };
int n = arr.Length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
Console.WriteLine(countSubarrays(arr, n, k));
}
}
/* This code contributed by PrinciRaj1992 */
4
进一步优化解决方案:可以理解,如果子数组[i..j]的乘积可被k整除,则所有子数组[i..t]的乘积也使得j
CPP
// C++ implementation of the approach
#include
using namespace std;
#define MAX 100005
typedef long long ll;
// Segment tree implemented as an array
ll tree[MAX << 2];
// Function to build segment tree
void build(int node, int start, int end, const int* arr, int k)
{
if (start == end) {
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
ll query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
ll q1 = query(2 * node, start, mid, l, r, k);
ll q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
ll countSubarrays(int* arr, int n, int k)
{
ll ans = 0;
for (int i = 0; i < n; i++) {
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high) {
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
cout << countSubarrays(arr, n, k);
return 0;
}
Java
// Java implementation of the approach
class GFG
{
static int MAX = 100005;
// Segment tree implemented as an array
static int tree[] = new int[MAX << 2];
// Function to build segment tree
static void build(int node, int start,
int end, int arr[], int k)
{
if (start == end) {
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
static int query(int node, int start, int end, int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
int q1 = query(2 * node, start, mid, l, r, k);
int q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
static int countSubarrays(int arr[], int n, int k)
{
int ans = 0;
for (int i = 0; i < n; i++)
{
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high)
{
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
public static void main(String[] args)
{
int arr[] = { 6, 2, 8 };
int n = arr.length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
System.out.println(countSubarrays(arr, n, k));
}
}
// This code is contributed by divyesh072019
Python3
# Python3 implementation of the approach
MAX = 100005
# Segment tree implemented as an array
tree = [0 for i in range(MAX << 2)];
# Function to build segment tree
def build(node, start, end, arr, k):
if (start == end):
tree[node] = arr[start] % k;
return;
mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
# Function to query product % k
# of sub-array[l..r]
def query(node, start, end, l, r, k):
if (start > end or start > r or end < l):
return 1;
if (start >= l and end <= r):
return tree[node] % k;
mid = (start + end) >> 1;
q1 = query(2 * node, start, mid, l, r, k);
q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
# Function to return the count of sub-arrays
# whose product is divisible by K
def countSubarrays(arr, n, k):
ans = 0;
for i in range(n):
low = i
high = n - 1;
# Binary search
# Check if sub-array[i..mid] satisfies the constraint
# Adjust low and high accordingly
while (low <= high):
mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0):
high = mid - 1;
else:
low = mid + 1;
ans += n - low;
return ans;
# Driver code
if __name__=='__main__':
arr = [ 6, 2, 8 ]
n = len(arr)
k = 4;
# Build the segment tree
build(1, 0, n - 1, arr, k);
print(countSubarrays(arr, n, k))
# This code is contributed by rutvik_56.
C#
// C# implementation of the approach
using System;
using System.Collections.Generic;
class GFG
{
static int MAX = 100005;
// Segment tree implemented as an array
static int[] tree = new int[MAX << 2];
// Function to build segment tree
static void build(int node, int start,
int end, int[] arr, int k)
{
if (start == end)
{
tree[node] = arr[start] % k;
return;
}
int mid = (start + end) >> 1;
build(2 * node, start, mid, arr, k);
build(2 * node + 1, mid + 1, end, arr, k);
tree[node] = (tree[2 * node] * tree[2 * node + 1]) % k;
}
// Function to query product % k
// of sub-array[l..r]
static int query(int node, int start, int end,
int l, int r, int k)
{
if (start > end || start > r || end < l)
return 1;
if (start >= l && end <= r)
return tree[node] % k;
int mid = (start + end) >> 1;
int q1 = query(2 * node, start, mid, l, r, k);
int q2 = query(2 * node + 1, mid + 1, end, l, r, k);
return (q1 * q2) % k;
}
// Function to return the count of sub-arrays
// whose product is divisible by K
static int countSubarrays(int[] arr, int n, int k)
{
int ans = 0;
for (int i = 0; i < n; i++)
{
int low = i, high = n - 1;
// Binary search
// Check if sub-array[i..mid] satisfies the constraint
// Adjust low and high accordingly
while (low <= high)
{
int mid = (low + high) >> 1;
if (query(1, 0, n - 1, i, mid, k) == 0)
high = mid - 1;
else
low = mid + 1;
}
ans += n - low;
}
return ans;
}
// Driver code
static void Main() {
int[] arr = { 6, 2, 8 };
int n = arr.Length;
int k = 4;
// Build the segment tree
build(1, 0, n - 1, arr, k);
Console.Write(countSubarrays(arr, n, k));
}
}
// This code is contributed by divyeshrbadiya07
4
两个指针技术:与二进制搜索讨论类似,很明显,如果子数组[i..j]的乘积可被k整除,则所有子数组[i..t]都使j
因此,对应于上述事实,这里也可以应用两指针技术。两个指针L,R取与升指向当前子阵列和r指示的开始到当前子阵列的端部。如果子阵列[l..r]的乘积可被k整除,则所有子阵列[l..s]使得r count = count + n – r。由于需要在当前子数组中添加和删除元素,因此无法简单地获取整个子数组的乘积,因为以这种方式添加和删除元素会很麻烦。
取而代之的是,在O(sqrt(n))时间中对k进行质因子分解,并将其质因子存储在STL映射中。另一个映射用于维护当前子数组中素数的计数,在这种情况下,可以将其称为当前映射。然后,每当需要在当前子数组中添加元素时,就会将这些素数的计数添加到当前映射中,这些素数在k的素因数分解中发生。每当需要从当前映射中删除元素时,素数的计数都会类似地减去。
下面是上述方法的实现。
CPP
// C++ implementation of the approach
#include
using namespace std;
#define ll long long
#define MAX 100002
#define pb push_back
// Vector to store primes
vector primes;
// k_cnt stores count of prime factors of k
// current_map stores the count of primes
// in the current sub-array
// cnts[] is an array of maps which stores
// the count of primes for element at index i
unordered_map k_cnt, current_map, cnts[MAX];
// Function to store primes in
// the vector primes
void sieve()
{
int prime[MAX];
prime[0] = prime[1] = 1;
for (int i = 2; i < MAX; i++) {
if (prime[i] == 0) {
for (int j = i * 2; j < MAX; j += i) {
if (prime[j] == 0) {
prime[j] = i;
}
}
}
}
for (int i = 2; i < MAX; i++) {
if (prime[i] == 0) {
prime[i] = i;
primes.pb(i);
}
}
}
// Function to count sub-arrays whose product
// is divisible by k
ll countSubarrays(int* arr, int n, int k)
{
// Special case
if (k == 1) {
cout << (1LL * n * (n + 1)) / 2;
return 0;
}
vector k_primes;
for (auto p : primes) {
while (k % p == 0) {
k_primes.pb(p);
k /= p;
}
}
// If k is prime and is more than 10^6
if (k > 1) {
k_primes.pb(k);
}
for (auto num : k_primes) {
k_cnt[num]++;
}
// Two pointers initialized
int l = 0, r = 0;
ll ans = 0;
while (r < n) {
// Add rth element to the current segment
for (auto& it : k_cnt) {
// p = prime factor of k
int p = it.first;
while (arr[r] % p == 0) {
current_map[p]++;
cnts[r][p]++;
arr[r] /= p;
}
}
// Check if current sub-array's product
// is divisible by k
int flag = 0;
for (auto& it : k_cnt) {
int p = it.first;
if (current_map[p] < k_cnt[p]) {
flag = 1;
break;
}
}
// If for all prime factors p of k,
// current_map[p] >= k_cnt[p]
// then current sub-array is divisible by k
if (!flag) {
// flag = 0 means that after adding rth element
// segment's product is divisible by k
ans += n - r;
// Eliminate 'l' from the current segment
for (auto& it : k_cnt) {
int p = it.first;
current_map[p] -= cnts[l][p];
}
l++;
}
else {
r++;
}
}
return ans;
}
// Driver code
int main()
{
int arr[] = { 6, 2, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
int k = 4;
sieve();
cout << countSubarrays(arr, n, k);
return 0;
}
4