String

文字列アルゴリズム詰め合わせです。 文字列に関する様々なアルゴリズムが入っています。

文字列 s の $a$ 番目から $b - 1$ 番目の要素のsubstringを、s[a..b)と表記します。

suffix_array

(1) vector<int> suffix_array(string s)
(2) vector<int> suffix_array<T>(vector<T> s)
(3) vector<int> suffix_array(vector<int> s, int upper)

長さ $n$ の文字列 s のSuffix Arrayとして、長さ $n$ の vector を返す。 Suffix Array sa は $(0, 1, \dots, n - 1)$ の順列であって、各 $i = 0,1, \cdots ,n-2$ について s[sa[i]..n) < s[sa[i+1]..n) を満たすもの。

制約

計算量

lcp_array

(1) vector<int> lcp_array(string s, vector<int> sa)
(2) vector<int> lcp_array<T>(vector<T> s, vector<int> sa)

長さ $n$ の文字列 s のLCP Arrayとして、長さ $n-1$ の配列を返す。$i$ 番目の要素は s[sa[i]..n), s[sa[i+1]..n) の LCP(Longest Common Prefix) の長さ。

制約

計算量

z_algorithm

(1) vector<int> z_algorithm(string s)
(2) vector<int> z_algorithm<T>(vector<T> s)

入力の長さを $n$ として、長さ $n$ の配列を返す。 $i$ 番目の要素は s[0..n)s[i..n)のLCP(Longest Common Prefix)の長さ。

制約

計算量

使用例

How to Use

#include <atcoder/string> #include <string> #include <vector> using namespace std; using namespace atcoder; int main() { string s = "missisippi"; vector<int> sa = suffix_array(s); vector<string> answer = { "i", "ippi", "isippi", "issisippi", "missisippi", "pi", "ppi", "sippi", "sisippi", "ssisippi", }; assert(sa.size() == answer.size()); for (int i = 0; i < int(sa.size()); i++) { assert(s.substr(sa[i]) == answer[i]); } }

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

#include <atcoder/string> #include <iostream> #include <string> #include <vector> using namespace std; using namespace atcoder; int main() { static char buf[500'001]; scanf("%s", buf); string s = buf; vector<int> sa = suffix_array(s); long long answer = 1LL * s.size() * (s.size() + 1) / 2; for (auto x : lcp_array(s, sa)) { answer -= x; } printf("%lld\n", answer); return 0; }