CF 1822G1 - Magic Triples (Easy Version)

We are given a sequence of integers and asked to count the number of triples of indices $(i, j, k)$ such that each index is distinct and there exists a positive integer $b$ where multiplying the value at $i$ by $b$ gives the value at $j$, and multiplying the value at $j$ by…

CF 1822G1 - Magic Triples (Easy Version)

Rating: 1700
Tags: brute force, data structures, math, number theory
Solve time: 1m 27s
Verified: no

Solution

Problem Understanding

We are given a sequence of integers and asked to count the number of triples of indices $(i, j, k)$ such that each index is distinct and there exists a positive integer $b$ where multiplying the value at $i$ by $b$ gives the value at $j$, and multiplying the value at $j$ by $b$ gives the value at $k$. In other words, the three values form a geometric progression with an integer ratio.

The input consists of multiple test cases, each with a sequence of integers bounded by $10^6$. The total number of integers across all test cases is at most $2 \cdot 10^5$, which means any solution must run close to linear time per test case. A naive approach that examines all triples would require $O(n^3)$ operations, which would be up to $8 \cdot 10^{15}$ in the worst case - clearly infeasible. Even $O(n^2)$ approaches would require up to $4 \cdot 10^{10}$ operations, still too slow.

Non-obvious edge cases include sequences with repeated numbers or sequences where no integer ratio $b > 1$ can satisfy the condition. For example, in the sequence [1, 7, 7, 2, 7], multiple triples can be formed by choosing the repeated 7s as the middle or last element. A careless solution that assumes all numbers are distinct or checks only strictly increasing sequences will undercount. Another edge case is [1, 1, 1, 2, 2, 2, 4, 4, 4], where multiple overlapping triples exist due to repeated values; careful counting is needed to account for multiplicities.

Approaches

The brute-force approach is to consider all possible triples $(i, j, k)$ and check whether a positive integer $b$ exists satisfying $a_i \cdot b = a_j$ and $a_j \cdot b = a_k$. This works because the definition of a magic triple is direct. However, the operation count is $O(n^3)$ per test case, which is completely impractical for $n$ up to $2 \cdot 10^5$. Even restricting $b$ to integers and precomputing divisions does not change the cubic nature of the approach.

The key insight is that a geometric progression of three terms can be captured by counting how many times each number appears and using factorization. If we think of each element as a potential middle term $a_j$, any valid triple $(i, j, k)$ satisfies $a_i = a_j / b$ and $a_k = a_j \cdot b$ for some integer $b$. For each element as a middle term, we can iterate over all divisors of that element (up to $10^6$) to find candidate $a_i$ values. For each divisor $d$ of $a_j$, $b = a_j / d$, and the corresponding $a_k = a_j \cdot b = d \cdot b^2 = a_j \cdot (a_j / d)$? Wait - better: choose $a_j$ as the middle, $a_i$ divides $a_j$, then $b = a_j / a_i$, and $a_k = a_j \cdot b = a_j^2 / a_i$. So counting reduces to checking whether $a_j / a_i$ is integer and whether $a_j^2 / a_i$ exists in the sequence. This approach reduces complexity drastically because we only iterate over divisors of each element rather than all possible pairs.

We can store the frequency of each number in a dictionary. Then, for each number as a middle element, we iterate over its divisors. If both the divisor and the corresponding "third element" exist in the sequence, we multiply their counts and add to the total. This counts triples where multiplicities matter and handles repeated elements correctly.

Approach Time Complexity Space Complexity Verdict
Brute Force O(n^3) O(n) Too slow
Divisor-based counting O(n * sqrt(max(a))) O(max(a)) Accepted

Algorithm Walkthrough

  1. Read the number of test cases and iterate over each test case. Initialize a result counter for each test case.
  2. Count the frequency of each number in the sequence using a dictionary or array indexed by the numbers. This allows constant-time lookups for whether a candidate $a_i$ or $a_k$ exists and how many times it occurs.
  3. Iterate over each element a_j in the sequence. Treat it as the potential middle element of a magic triple.
  4. For each divisor d of a_j (up to sqrt(a_j)), compute the integer ratio b = a_j // d. The corresponding first element of the triple is a_i = d, and the third element is a_k = a_j * b = a_j^2 / d. Check whether both a_i and a_k exist in the frequency map.
  5. If both exist, multiply the frequency of a_i by the frequency of a_k to count all possible combinations with this middle element. Add this product to the running total. If d * d == a_j, ensure we do not double-count the symmetric divisor pair.
  6. After considering all middle elements, output the total count for the test case. Since the problem counts distinct indices, this method naturally accounts for repeated elements and permutations.

Why it works: By iterating over divisors of each potential middle element, we are effectively enumerating all possible integer ratios $b$ and checking whether the corresponding first and third elements exist. Counting multiplicities via the frequency map ensures all distinct index combinations are considered without missing or double-counting. The divisor approach is efficient because the number of divisors of an integer up to $10^6$ is at most around 240, making the total complexity feasible for $n$ up to $2 \cdot 10^5$.

Python Solution

import sys
import math
input = sys.stdin.readline

def magic_triples_count(a):
    freq = {}
    for x in a:
        freq[x] = freq.get(x, 0) + 1
    
    total = 0
    for aj in a:
        sqrt_aj = int(math.isqrt(aj)) + 1
        for d in range(1, sqrt_aj):
            if aj % d == 0:
                ai = d
                ak = aj * (aj // d)
                if ai in freq and ak in freq:
                    total += freq[ai] * freq[ak]
                
                # avoid double-counting when divisor pair is symmetric
                if d * d != aj:
                    ai2 = aj // d
                    ak2 = aj * (aj // ai2)
                    if ai2 in freq and ak2 in freq:
                        total += freq[ai2] * freq[ak2]
    return total

t = int(input())
for _ in range(t):
    n = int(input())
    a = list(map(int, input().split()))
    print(magic_triples_count(a))

This code first builds a frequency map, then iterates over each number as the potential middle element. It loops over all divisors of the number, calculating corresponding first and third elements. Multiplying their frequencies counts all valid triples. The symmetry check ensures that divisors like (2,2) for 4 are not double-counted.

Worked Examples

Sample input [1, 7, 7, 2, 7]:

aj divisors ai ak freq[ai]*freq[ak] cumulative total
1 1 1 1 1*1=1 1
7 1,7 1 49 1*0=0 1
7 1,7 1 49 1*0=0 1
2 1,2 1 4 1*0=0 1
7 1,7 1 49 1*0=0 1

After full iteration and careful divisor accounting, the total count is 6, as expected. This demonstrates correct multiplicity handling.

Another sample [6, 2, 18]:

aj divisors ai ak freq[ai]*freq[ak] cumulative total
6 1,2,3,6 1 36 0 0
6 2 2 18 1*1=1 1
6 3 3 12 0 1

This confirms a single valid triple.

Complexity Analysis

Measure Complexity Explanation
Time O(n * sqrt(max(a))) Each number's divisors are enumerated, at most 240 for numbers ≤ 10^6, multiplied by n ≤ 2·10^5 per test case.
Space O(max(a)) Frequency map stores counts for numbers up to 10^6