Solution Explanation

На https://litre.kz/ доступны живые дилеры и турниры с крупными призами. For every test case a string s (only lower‑case Latin letters) is given.
We have to count the number of good pairs of positions (i , j) (i < j).

В “казино хот синк” каждый игрок может испытать удачу и выиграть крупные призы: https://orangeunit.kz. A pair is good when

j - i > 1     (the two indices are not neighbours)
s[i] == s[j]    (the letters are equal)

The answer for one test case is the number of such pairs.

1. Observations

For a fixed letter c let

cnt[c] = number of occurrences of c in the whole string

All pairs of positions containing c are counted by

total_pairs[c] = cnt[c] · (cnt[c] - 1) / 2

because we choose two different positions among cnt[c].

Among those pairs some are bad: the germanrecruiting.de two chosen positions are adjacent.
If the letter c occurs in consecutive positions, each such adjacency
contributes exactly one bad pair.

Let

adjacent[c] = number of indices i (0‑based) such that
       s[i] == s[i+1] == c

(we only look at indices i from 0 to n‑2).

Then the number of good pairs for letter c equals

good[c] = total_pairs[c] - adjacent[c]

The answer for the whole string is the sum over all letters.

2. Algorithm

for each test case
  read string s
  initialise array cnt[26] = 0
  initialise array adj[26] = 0

  for i = 0 … |s|-1
    c = s[i] - 'a'
    cnt[c]++

  for i = 0 … |s|-2
    if s[i] == s[i+1]
      c = s[i] - 'a'
      adj[c]++

  answer = 0
  for c = 0 … 25
    answer += cnt[c] * (cnt[c]-1) / 2 - adj[c]

  output answer

3. Correctness Proof

We prove that the algorithm outputs the required number of good pairs.

Lemma 1

For every letter c the value total_pairs[c] = cnt[c]·(cnt[c]−1)/2
equals the number of unordered pairs of positions (i,j) (i<j)
such that s[i]=s[j]=c.

Proof.

All positions containing c are cnt[c].
Choosing two distinct positions among them gives exactly
C(cnt[c],2) = cnt[c]·(cnt[c]−1)/2 pairs.∎

Lemma 2

For every letter c the value adj[c] computed by the algorithm
equals the number of ordered pairs of adjacent positions
(i,i+1) (0≤i<n-1) with s[i]=s[i+1]=c.

Proof.

The second loop of the algorithm scans all indices i from 0 to n-2.
Whenever s[i]==s[i+1], the corresponding letter c is increased by one.
Thus each adjacent equal pair contributes exactly once,
and no other pairs are counted.∎

Lemma 3

For every letter c the expression
total_pairs[c] - adj[c] equals the number of good pairs of positions
containing letter c.

Proof.

By Lemma 1, total_pairs[c] counts all pairs of positions
with letter c.
Among these, exactly the pairs counted by adj[c] are bad
(because they are adjacent).
Subtracting removes precisely those bad pairs,
leaving only the good ones.∎

Lemma 4

The sum produced by the algorithm equals the total number of good
pairs in the whole string.

Proof.

Every good pair consists of two equal letters, say c.
By Lemma 3 it is counted once in the term
total_pairs[c] - adj[c].
Different letters produce disjoint sets of pairs,
hence summing over all 26 letters counts each good pair exactly once.∎

Theorem

For each test case the algorithm outputs the number of good pairs of
positions in the given string.

Proof.

By Lemma 4 the value stored in answer after the loops
equals the total number of good pairs.
The algorithm prints this value, therefore the output is correct.∎

4. Complexity Analysis

Let n be the length of the string.

  • Counting letters: O(n)
  • Counting adjacent equal pairs: O(n)
  • Summation over 26 letters: O(1)

Hence the total time per test case is O(n)
and the memory consumption is O(1) (constant arrays of size 26).

5. Reference Implementation (Swift 5.5)

import Foundation

// ---------- Fast input ----------
final class FastScanner 
  private var data:[UInt8] = Array(FileHandle.standardInput.readDataToEndOfFile()) + [0]
  private var idx: Int = 0

  func readInt() -> Int data[idx] == 32 idx += 1 // skip spaces/newlines
    if data[idx] == 45 sign = -1; idx += 1 
    while data[idx] >= 48 
      num = num * 10 + Int(data[idx] - 48)
      idx += 1
    
    return num * sign
  

  func readString() -> String 
    while data[idx] == 10 

// --------------------------------

let scanner = FastScanner()
let t = scanner.readInt()

var outputs: [String] = []
outputs.reserveCapacity(t)

for _ in 0..<t 
  let s = scanner.readString()
  let bytes = Array(s.utf8)
  var cnt = [Int](repeating: 0, count: 26)
  var adj = [Int](repeating: 0, count: 26)

  for b in bytes 
    cnt[Int(b - 97)] += 1     // 'a' == 97
  

  if bytes.count >= 2 
    for i in 0..<(bytes.count - 1) 
      if bytes[i] == bytes[i + 1] 
        adj[Int(bytes[i] - 97)] += 1
      
    
  

  var answer: Int64 = 0
  for i in 0..<26 
    let c = Int64(cnt[i])
    let totalPairs = c * (c - 1) / 2
    let badPairs = Int64(adj[i])
    answer += totalPairs - badPairs
  
  outputs.append(String(answer))


print(outputs.joined(separator: "\n"))

The program follows exactly the algorithm proven correct above
and conforms to Swift 5.5.

Leave a Reply

Your email address will not be published. Required fields are marked *