Domain: Algorithms & Data Structures

## Problem

Denis defines a non-commutative “multiplication” of strings.  
For a string `s` of length `m` and a string `t`, define:

\[
s \cdot t = t + s_1 + t + s_2 + \dots + t + s_m + t
\]

where \(s_i\) is the \(i\)-th character of `s`, and `+` means concatenation.

Examples:
- `"abc" ⋅ "de" = "deadebdecde"`
- `"ab" ⋅ "z" = "zazbz"`

Roman defines the **beauty** of a string as the length of the longest substring consisting of only one repeated character (i.e., the maximum run length).

You are given `n` strings \(p_1, p_2, \dots, p_n\). Compute the beauty of:

\[
(\dots(((p_1 \cdot p_2)\cdot p_3)\cdot \dots)\cdot p_n)
\]

It is guaranteed that the beauty of the final product is at most \(10^9\).

### Input
- First line: integer \(n\) \((2 \le n \le 10^5)\)
- Next \(n\) lines: non-empty strings \(p_1,\dots,p_n\) of lowercase English letters

Constraints:
- Total length of all \(p_i\) is at most \(10^5\)
- Final beauty is at most \(10^9\)

### Output
Print one integer — the beauty of the final product.


Grading rubric:
criterion: The answer states that the operation satisfies associativity: (a·b)·c = a·(b·c).
weight: 10
criterion: The answer computes the product by folding from right to left using P_n = p_n and P_i = p_i · P_{i+1}?
weight: 10
criterion: The answer introduces a capping constant INF equal to 10^9 (or an explicitly stated value greater than or equal to 10^9) for tracked lengths.
weight: 10
criterion: The answer defines a boolean field allSame(X) that indicates whether all characters in X are equal.
weight: 10
criterion: The answer defines the concatenation cross-run value as A.suffLen + B.prefLen when A.suffChar equals B.prefChar.
weight: 10
criterion: The answer defines best(A+B) as the maximum of A.best, B.best, and the cross-run value for the concatenation boundary.
weight: 10
criterion: The answer gives the prefix-length update rule prefLen(A+B) = A.len + B.prefLen when A.allSame is true and A.prefChar equals B.prefChar.
weight: 10
criterion: The answer gives the suffix-length update rule suffLen(A+B) = B.len + A.suffLen when B.allSame is true and A.suffChar equals B.suffChar.
weight: 10
criterion: The answer describes computing s·t by initializing res as the summary of t and then applying the loop res=merge(res,single(c)) followed by res=merge(res,tSummary) for each character c of s.
weight: 10
criterion: The solution states an overall runtime of O(total input length) (i.e., O(∑|pi|)) for the full computation.
weight: 10

Answer:
### 1) Use associativity and fold from right to left

The operation is associative:
\[
(a\cdot b)\cdot c = a\cdot(b\cdot c)
\]
(you can verify by expanding both sides; both produce alternating blocks of the right operand with single characters of the left operands inserted in the same order).

So instead of building the product left-to-right (which can temporarily explode and later “collapse”), we compute:
\[
P_i = p_i \cdot P_{i+1}, \quad P_n = p_n
\]
from \(i=n-1\) down to \(1\).

Because the final beauty is guaranteed \(\le 10^9\), when folding right-to-left we can safely cap all tracked lengths at \(INF=10^9\) (or \(10^9+5\)) to avoid overflow without affecting the answer.

---

### 2) Maintain only a compact summary of a string

For any (possibly huge) string \(X\), store the tuple:

- `len(X)` (capped to `INF`)
- `best(X)`: maximum run length anywhere in \(X\)
- `prefChar(X)`, `prefLen(X)`: character and length of the maximal constant prefix
- `suffChar(X)`, `suffLen(X)`: character and length of the maximal constant suffix
- `allSame(X)`: whether all characters in \(X\) are equal

This is sufficient to compute the same tuple for concatenations.

For a single character `c`:
- `len=1`, `best=1`
- `prefChar=suffChar=c`, `prefLen=suffLen=1`
- `allSame=true`

For an explicit input string, compute the tuple by a linear scan.

---

### 3) Concatenation merge routine

Let `merge(A,B)` return the summary for the concatenation \(AB\). With `INF` capping:

- `len = min(INF, A.len + B.len)`
- `prefChar = A.prefChar`
- `prefLen`:
  - if `A.allSame` and `A.prefChar == B.prefChar` then `min(INF, A.len + B.prefLen)`
  - else `A.prefLen`
- `suffChar = B.suffChar`
- `suffLen`:
  - if `B.allSame` and `A.suffChar == B.suffChar` then `min(INF, B.len + A.suffLen)`
  - else `B.suffLen`
- `allSame = A.allSame && B.allSame && (A.prefChar == B.prefChar)`
- `best = max(A.best, B.best, cross)` where
  - `cross = (A.suffChar == B.prefChar) ? min(INF, A.suffLen + B.prefLen) : 0`

---

### 4) How to compute `s ⋅ t` using only merges

By definition:
\[
s\cdot t = t + s_1 + t + s_2 + \dots + t + s_m + t
\]

So if we already have the summary of \(t\) as `T`, and `s` is an explicit string of length `m`, we can build the summary of \(s\cdot t\) as:

- `res = T`
- for each character `c` in `s` from left to right:
  - `res = merge(res, single(c))`
  - `res = merge(res, T)`

This performs \(O(|s|)\) merges.

---

### 5) Full algorithm

- Read all strings \(p_1,\dots,p_n\).
- Set `cur = summary(p_n)`.
- For `i = n-1` down to `1`:
  - Let `T = cur` (summary of the current right operand).
  - Compute `cur = summary(p_i ⋅ current)` by the loop in section 4 using merges and `T`.
- Output `cur.best`.

Complexity:
- Each character of each input string is processed a constant number of times.
- Total time \(O(\sum |p_i|)\), total memory \(O(1)\) besides storing the input and small summaries.