Three Occurrences (Codeforces 1418G)
Tags: Others, hashing

You are given an array $$$a$$$ consisting of $$$n$$$ integers. We denote the subarray $$$a[l..r]$$$ as the array $$$[a_l, a_{l + 1}, \dots, a_r]$$$ ($$$1 \le l \le r \le n$$$).A subarray is considered good if every integer that occurs in this subarray occurs there exactly thrice. For example, the array $$$[1, 2, 2, 2, 1, 1, 2, 2, 2]$$$ has three good subarrays:  $$$a[1..6] = [1, 2, 2, 2, 1, 1]$$$;  $$$a[2..4] = [2, 2, 2]$$$;  $$$a[7..9] = [2, 2, 2]$$$. Calculate the number of good subarrays of the given array $$$a$$$.

Input: The first line contains one integer $$$n$$$ ($$$1 \le n \le 5 \cdot 10^5$$$).The second line contains $$$n$$$ integers $$$a_1$$$, $$$a_2$$$, ..., $$$a_n$$$ ($$$1 \le a_i \le n$$$).

Output: Print one integer — the number of good subarrays of the array $$$a$$$.


Sample Inputs:
9
1 2 2 2 1 1 2 2 2

10
1 2 3 4 1 2 3 1 2 3

12
1 2 3 4 3 4 2 1 3 4 2 1

Sample Outputs:
3

0

1

Solution (Python):
from collections import Counter
from random import randint
import sys
input = sys.stdin.buffer.readline

def prog():
    n = int(input())
    a = list(map(int, input().split()))
    curr_occurences = [0] * (n + 1)
    mult = [randint(1, 10 ** 20) for i in range(n + 1)]
    hash_at_idx = [0] * (n + 1)
    hashes = Counter([0])
    curr_hash = 0
    last_3 = [[] for i in range(n + 1)]
    ans = 0
    least_start = -1
    for i in range(n):
        x = a[i]
        if len(last_3[x]) == 3:
            new_start = last_3[x][0]
            while least_start < new_start:
                hashes[hash_at_idx[least_start]] -= 1
                least_start += 1
            del last_3[x][0]
        curr_hash -= curr_occurences[x] * mult[x]
        curr_occurences[x] = (curr_occurences[x] + 1) % 3
        curr_hash += curr_occurences[x] * mult[x]
        ans += hashes[curr_hash]
        hashes[curr_hash] += 1
        hash_at_idx[i] = curr_hash
        last_3[x].append(i)
    print(ans)
prog()

Solution (Python):
from collections import Counter
from random import randint
import sys
input = sys.stdin.buffer.readline

def prog():
    n = int(input())
    a = list(map(int, input().split()))
    curr_occurences = [0] * (n + 1)
    mult = [randint(1, 10 ** 20) for i in range(n + 1)]
    hash_at_idx = [0] * (n + 1)
    hashes = Counter([0])
    curr_hash = 0
    last_3 = [[] for i in range(n + 1)]
    ans = 0
    least_start = -1
    for i in range(n):
        x = a[i]
        if len(last_3[x]) == 3:
            new_start = last_3[x][0]
            while least_start < new_start:
                hashes[hash_at_idx[least_start]] -= 1
                least_start += 1
            del last_3[x][0]
        curr_hash -= curr_occurences[x] * mult[x]
        curr_occurences[x] = (curr_occurences[x] + 1) % 3
        curr_hash += curr_occurences[x] * mult[x]
        ans += hashes[curr_hash]
        hashes[curr_hash] += 1
        hash_at_idx[i] = curr_hash
        last_3[x].append(i)
    print(ans)
prog()

Solution (Python):
from collections import Counter
from random import randint
import sys
input = sys.stdin.buffer.readline

def prog():
    n = int(input())
    a = list(map(int, input().split()))
    curr_occurences = [0] * (n + 1)
    mult = [randint(1, 10 ** 20) for i in range(n + 1)]
    hash_at_idx = [0] * (n + 1)
    hashes = Counter([0])
    curr_hash = 0
    last_3 = [[] for i in range(n + 1)]
    ans = 0
    least_start = -1
    for i in range(n):
        x = a[i]
        if len(last_3[x]) == 3:
            new_start = last_3[x][0]
            while least_start < new_start:
                hashes[hash_at_idx[least_start]] -= 1
                least_start += 1
            del last_3[x][0]
        curr_hash -= curr_occurences[x] * mult[x]
        curr_occurences[x] = (curr_occurences[x] + 1) % 3
        curr_hash += curr_occurences[x] * mult[x]
        ans += hashes[curr_hash]
        hashes[curr_hash] += 1
        hash_at_idx[i] = curr_hash
        last_3[x].append(i)
    print(ans)
prog()