<p>You are <strong>building</strong> a string <code>s</code> of length <code>n</code> <strong>one</strong> character at a time, <strong>prepending</strong> each new character to the <strong>front</strong> of the string. The strings are labeled from <code>1</code> to <code>n</code>, where the string with length <code>i</code> is labeled <code>s<sub>i</sub></code>.</p>

<ul>
	<li>For example, for <code>s = &quot;abaca&quot;</code>, <code>s<sub>1</sub> == &quot;a&quot;</code>, <code>s<sub>2</sub> == &quot;ca&quot;</code>, <code>s<sub>3</sub> == &quot;aca&quot;</code>, etc.</li>
</ul>

<p>The <strong>score</strong> of <code>s<sub>i</sub></code> is the length of the <strong>longest common prefix</strong> between <code>s<sub>i</sub></code> and <code>s<sub>n</sub></code> (Note that <code>s == s<sub>n</sub></code>).</p>

<p>Given the final string <code>s</code>, return<em> the <strong>sum</strong> of the <strong>score</strong> of every </em><code>s<sub>i</sub></code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;babab&quot;
<strong>Output:</strong> 9
<strong>Explanation:</strong>
For s<sub>1</sub> == &quot;b&quot;, the longest common prefix is &quot;b&quot; which has a score of 1.
For s<sub>2</sub> == &quot;ab&quot;, there is no common prefix so the score is 0.
For s<sub>3</sub> == &quot;bab&quot;, the longest common prefix is &quot;bab&quot; which has a score of 3.
For s<sub>4</sub> == &quot;abab&quot;, there is no common prefix so the score is 0.
For s<sub>5</sub> == &quot;babab&quot;, the longest common prefix is &quot;babab&quot; which has a score of 5.
The sum of the scores is 1 + 0 + 3 + 0 + 5 = 9, so we return 9.</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> s = &quot;azbazbzaz&quot;
<strong>Output:</strong> 14
<strong>Explanation:</strong> 
For s<sub>2</sub> == &quot;az&quot;, the longest common prefix is &quot;az&quot; which has a score of 2.
For s<sub>6</sub> == &quot;azbzaz&quot;, the longest common prefix is &quot;azb&quot; which has a score of 3.
For s<sub>9</sub> == &quot;azbazbzaz&quot;, the longest common prefix is &quot;azbazbzaz&quot; which has a score of 9.
For all other s<sub>i</sub>, the score is 0.
The sum of the scores is 2 + 3 + 9 = 14, so we return 14.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= s.length &lt;= 10<sup>5</sup></code></li>
	<li><code>s</code> consists of lowercase English letters.</li>
</ul>



import sys

import random

DEFAULT_PRIME = 2**31 - 1
# DEFAULT_PRIME = 2**16 + 1
DEFAULT_ELEMENT = random.randint(2, DEFAULT_PRIME - 1)

class RangeHash:
  def __init__(self, modulus = DEFAULT_PRIME, element = DEFAULT_ELEMENT):
    self.modulus = modulus
    self.element = element % modulus

    self.powers = []
    self.lookup = []

  def Process(self, S):
    self.N = len(S)

    acc = 1
    hash = 0

    for i in range(self.N):
      hash = (hash * self.element + ord(S[i])) % self.modulus
      self.lookup.append(hash)
      self.powers.append(acc)
      acc = (acc * self.element) % self.modulus

    self.lookup.append(0)
    self.powers.append(1)

  def GetLength(self):
    return self.N

  def GetHash(self, left, right):
      whole = self.lookup[right]
      prefix = self.lookup[left - 1]

      span = right - left + 1

      return (whole - (prefix * self.powers[span])) % self.modulus

def HasCommonPrefix(R: RangeHash, si, length):
  N = R.GetLength()

  h_complete = R.GetHash(0, length - 1)
  h_suffix = R.GetHash(N - si, N - si + length - 1)

  return h_complete == h_suffix

"""
Returns length of the longest shared prefix between:
- Entire string
- Suffix with index "si" (where k-th suffix contains the last k characters)
"""
def LongestCommonPrefix(R, si):
  upper_bound = si
  lower_bound = 0

  while lower_bound < upper_bound:
    middle = (lower_bound + upper_bound + 1) // 2
    if HasCommonPrefix(R, si, middle):
      lower_bound = middle
    else:
      upper_bound = middle - 1

  return lower_bound

def TotalScore(S):
    R = RangeHash()
    R.Process(S)

    n = len(S)

    total = 0

    first_letter = S[0]

    for i in range(1, n):
        suffix = S[n - i : n]
        if S[-i] != first_letter:
            continue
        optimal = LongestCommonPrefix(R, i)
        # print('%s vs %s → %d' % (suffix, S, optimal))
        total += optimal

    total += n

    return total

class Solution:
    def sumScores(self, s: str) -> int:
        return TotalScore(s)

26400