# acl_cpp.string

- [C++ 版のドキュメント](https://atcoder.github.io/ac-library/production/document_ja/string.html)
- [ソースコード](https://github.com/tatyam-prime/acl-cpp-python/blob/main/src/string.cpp)

```python
from acl_cpp.string import suffix_array, lcp_array, z_algorithm
```

## string.suffix_array

```python
# (1) vector<int> suffix_array(string s)
def suffix_array(s: str) -> list[int]

# (2) vector<int> suffix_array<ll>(vector<ll> s)   
def suffix_array(s: list[int]) -> list[int]

# (3) vector<int> suffix_array(vector<int> s, int upper)
def suffix_array(s: list[int], upper: int) -> list[int]
```

$n = \text{len}(s)$ として、以下で定める長さ $n$ の配列 `sa` を返します。

- `sa` は $(0, 1, \ldots, n-1)$ の順列である
- `s[sa[i]:] < s[sa[i+1]:]` を満たす

**制約**

- (2) $-2^{63} \leq s[i] \lt 2^{63}$
- (3) $0 \leq s[i] \leq \text{upper} \lt 2^{31}$

**計算量**

- (1) $O(n)$
- (2) $O(n \log n)$ 時間, $O(n)$ 空間
- (3) $O(n + \mathrm{upper})$

## string.lcp_array

```python
# (1) vector<int> lcp_array(string s, vector<int> sa)
def lcp_array(s: str, sa: list[int]) -> list[int]

# (2) vector<int> lcp_array<ll>(vector<ll> s, vector<int> sa)
def lcp_array(s: list[int], sa: list[int]) -> list[int]
```

$n = \text{len}(s)$ として、以下で定める長さ $n-1$ の配列 `lcp` を返します。

- `lcp[i]` は `s[sa[i]:]` と `s[sa[i+1]:]` の LCP (Longest Common Prefix) の長さ

**制約**

- <span style="color: red;">`sa` は `s` の Suffix Array である</span>
    - これが満たされない場合の動作は未定義

**計算量**

- $O(n)$

## string.z_algorithm

```python
# (1) vector<int> z_algorithm(string s)
def z_algorithm(s: str) -> list[int]

# (2) vector<int> z_algorithm<ll>(vector<ll> s)
def z_algorithm(s: list[int]) -> list[int]
```

$n = \text{len}(s)$ として、以下で定める長さ $n$ の配列 `z` を返します。

- `z[i]` は `s` と `s[i:]` の LCP (Longest Common Prefix) の長さ

**制約**

- (2) $-2^{63} \leq s[i] \lt 2^{63}$

**計算量**

- $O(n)$

## 使用例

```python
from acl_cpp.string import suffix_array

s = "missisippi"
sa = suffix_array(s)

answer = [
    "i",
    "ippi",
    "isippi",
    "issisippi",
    "missisippi",
    "pi",
    "ppi",
    "sippi",
    "sisippi",
    "ssisippi",
]

for i, t in zip(sa, answer):
    assert s[i:] == t
```

AC code of <https://atcoder.jp/contests/practice2/tasks/practice2_i>

```python
from acl_cpp.string import suffix_array, lcp_array

s = input()
n = len(s)
sa = suffix_array(s)
lcp = lcp_array(s, sa)

print(n * (n - 1) // 2 - sum(lcp))
```