├── requirements.txt ├── notebook.pdf ├── .verify-helper ├── config.toml ├── docs │ ├── _config.yml │ └── index.md └── timestamps.remote.json ├── package.json ├── src ├── template │ ├── hash.sh │ ├── settings.sh │ └── template.hpp ├── string │ ├── KMP.hpp │ ├── Zalgorithm.hpp │ ├── Manacher.hpp │ ├── RollingHash.hpp │ └── SuffixArray.hpp ├── math │ ├── ExtGCD.hpp │ └── BinaryGCD.hpp ├── modint │ ├── BarrettReduction.hpp │ └── modint.hpp ├── flow │ └── 燃やす埋める.md ├── data-structure │ ├── BIT.hpp │ └── FastSet.hpp ├── FPS │ ├── FFT.hpp │ └── FFT_fast.hpp ├── extra │ └── modint_fast.hpp └── memo │ └── Primes.md ├── docs ├── extra │ └── modint_fast.md ├── math │ ├── BinaryGCD.md │ └── ExtGCD.md ├── string │ ├── KMP.md │ ├── Manacher.md │ ├── Zalgorithm.md │ ├── SuffixArray.md │ └── RollingHash.md ├── modint │ ├── modint.md │ └── BarrettReduction.md ├── data-structure │ ├── BIT.md │ └── FastSet.md └── FPS │ ├── FFT_fast.md │ └── FFT.md ├── .gitignore ├── test ├── string │ ├── Zalgorithm.test.cpp │ ├── SuffixArray.test.cpp │ ├── LCP.test.cpp │ ├── KMP.test.cpp │ ├── Manacher.test.cpp │ └── RollingHash.test.cpp ├── template.test.cpp ├── template.hpp ├── math │ ├── BinaryGCD.test.cpp │ └── ExtGCD.test.cpp ├── FPS │ ├── FFT.test.cpp │ └── FFT_fast.test.cpp ├── modint │ ├── BarrettReduction.test.cpp │ └── modint.test.cpp ├── data-structure │ ├── BIT.test.cpp │ └── FastSet.test.cpp └── benchmark │ ├── SuffixArray.cpp │ ├── FastSet.cpp │ └── FFT.cpp ├── .clang-format ├── Makefile ├── LICENSE ├── .github └── workflows │ └── verify.yml └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | online-judge-verify-helper 2 | -------------------------------------------------------------------------------- /notebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tatyam-prime/ICPC_notebook/HEAD/notebook.pdf -------------------------------------------------------------------------------- /.verify-helper/config.toml: -------------------------------------------------------------------------------- 1 | [[languages.cpp.environments]] 2 | CXX = "g++" 3 | CXXFLAGS = ["-std=c++20", "-Wall", "-Wextra", "-Wshadow", "-O2"] 4 | -------------------------------------------------------------------------------- /.verify-helper/docs/_config.yml: -------------------------------------------------------------------------------- 1 | 2 | # generated by build/build.js 3 | title: 'ICPC Notebook' 4 | exclude: ['node_modules', 'test/benchmark'] 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "escape-html": "^1.0.3", 4 | "marked": "^12.0.0", 5 | "prismjs": "^1.29.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/template/hash.sh: -------------------------------------------------------------------------------- 1 | # 使い方: sh hash.sh -> コピペ -> Ctrl + D 2 | # コメント・空白・改行を削除して md5 でハッシュする 3 | g++ -dD -E -P -fpreprocessed - | tr -d '[:space:]' | md5sum | cut -c-6 4 | -------------------------------------------------------------------------------- /src/template/settings.sh: -------------------------------------------------------------------------------- 1 | # CLion の設定 2 | Settings → Build → CMake → Reload CMake Project 3 | add_compile_options(-D_GLIBCXX_DEBUG) 4 | # Caps Lock を Ctrl に変更 5 | setxkbmap -option ctrl:nocaps 6 | -------------------------------------------------------------------------------- /.verify-helper/docs/index.md: -------------------------------------------------------------------------------- 1 | みんなでつくる最強の ICPC 用ライブラリ (予定) 2 | 3 | - [ライブラリをまとめたページ](notebook.html) 4 | - [ライブラリをまとめた PDF](notebook.pdf) 5 | 6 | ### 前提要件 7 | 8 | - C++20 9 | - GCC 11 以上 10 | -------------------------------------------------------------------------------- /docs/extra/modint_fast.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 32 bit で加減算をちゃんと書いた Modint 3 | documentation_of: //src/extra/modint_fast.hpp 4 | --- 5 | 6 | modint の速度が欲しいときに使う 7 | PDF には含まれていません 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | .vscode/ 4 | .verify-helper/docs/static/base.css 5 | .verify-helper/docs/static/notebook.css 6 | .verify-helper/docs/static/notebook.html 7 | .verify-helper/docs/static/notebook.pdf 8 | -------------------------------------------------------------------------------- /docs/math/BinaryGCD.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Binary GCD 3 | documentation_of: //src/math/BinaryGCD.hpp 4 | --- 5 | 6 | 割り算を使わない高速な GCD 7 | 8 | ## 使い方 9 | 10 | - `u64 binary_gcd(u64 x, u64 y)`:$x$ と $y$ の最大公約数を計算する. 11 | - $O(\log(x + y))$ 時間 12 | -------------------------------------------------------------------------------- /src/string/KMP.hpp: -------------------------------------------------------------------------------- 1 | // kmp[i] := max{ l ≤ i | s[:l] == s[(i+1)-l:i+1] } 2 | // abacaba -> 0010123 3 | auto KMP(string s) { 4 | vector p(sz(s)); 5 | rep(i, 1, sz(s)) { 6 | ll g = p[i - 1]; 7 | while(g && s[i] != s[g]) g = p[g - 1]; 8 | p[i] = g + (s[i] == s[g]); 9 | } 10 | return p; 11 | } 12 | -------------------------------------------------------------------------------- /src/math/ExtGCD.hpp: -------------------------------------------------------------------------------- 1 | // returns gcd(a, b) and assign x, y to integers 2 | // s.t. ax + by = gcd(a, b) and |x| + |y| is minimized 3 | ll extgcd(ll a, ll b, ll& x, ll& y) { 4 | // assert(a >= 0 && b >= 0); 5 | if(!b) return x = 1, y = 0, a; 6 | ll d = extgcd(b, a % b, y, x); 7 | y -= a / b * x; 8 | return d; 9 | } 10 | -------------------------------------------------------------------------------- /src/math/BinaryGCD.hpp: -------------------------------------------------------------------------------- 1 | u64 ctz(u64 x) { return countr_zero(x); } 2 | u64 binary_gcd(u64 x, u64 y) { 3 | if(!x || !y) return x | y; 4 | u64 n = ctz(x), m = ctz(y); 5 | x >>= n, y >>= m; 6 | while(x != y) { 7 | if(x > y) x = (x - y) >> ctz(x - y); 8 | else y = (y - x) >> ctz(y - x); 9 | } 10 | return x << min(n, m); 11 | } 12 | -------------------------------------------------------------------------------- /test/string/Zalgorithm.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/zalgorithm" 2 | #include "test/template.hpp" 3 | #include "src/string/Zalgorithm.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | string S; 8 | cin >> S; 9 | auto z = Z(S); 10 | rep(i, 0, sz(S)) cout << z[i] << " \n"[i + 1 == sz(S)]; 11 | } 12 | -------------------------------------------------------------------------------- /test/template.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" 2 | #include "test/template.hpp" 3 | 4 | int main() { 5 | ll a = 0; 6 | assert(chmin(a, 1) == 0); 7 | assert(chmax(a, 1) == 1); 8 | assert(chmax(a, 1) == 0); 9 | assert(chmin(a, 0) == 1); 10 | puts("Hello World"); 11 | } 12 | -------------------------------------------------------------------------------- /src/string/Zalgorithm.hpp: -------------------------------------------------------------------------------- 1 | // Z[i] := LCP(s, s[i:]) 2 | // abacaba -> 7010301 3 | auto Z(string s) { 4 | ll n = sz(s), l = -1, r = -1; 5 | vector z(n, n); 6 | rep(i, 1, n) { 7 | ll& x = z[i] = i < r ? min(r - i, z[i - l]) : 0; 8 | while(i + x < n && s[i + x] == s[x]) x++; 9 | if(i + x > r) l = i, r = i + x; 10 | } 11 | return z; 12 | } 13 | -------------------------------------------------------------------------------- /test/template.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using ll = long long; 4 | const ll INF = LLONG_MAX / 4; 5 | #define rep(i, a, b) for(ll i = a; i < (b); i++) 6 | #define all(a) begin(a), end(a) 7 | #define sz(a) ssize(a) 8 | bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; } 9 | bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; } 10 | -------------------------------------------------------------------------------- /test/string/SuffixArray.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/suffixarray" 2 | #include "test/template.hpp" 3 | #include "src/string/SuffixArray.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | string S; 8 | cin >> S; 9 | const ll N = sz(S); 10 | auto [sa, lcp] = SA(S); 11 | rep(i, 0, N) cout << sa[i] << " \n"[i + 1 == N]; 12 | } 13 | -------------------------------------------------------------------------------- /test/string/LCP.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/number_of_substrings" 2 | #include "test/template.hpp" 3 | #include "src/string/SuffixArray.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | string S; 8 | cin >> S; 9 | const ll N = sz(S); 10 | auto [sa, lcp] = SA(S); 11 | cout << N * (N + 1) / 2 - accumulate(all(lcp), 0LL) << endl; 12 | } 13 | -------------------------------------------------------------------------------- /src/modint/BarrettReduction.hpp: -------------------------------------------------------------------------------- 1 | // using u64 = uint64_t; 2 | struct Barrett { // mod < 2^32 3 | u64 m, im; 4 | Barrett(u64 mod) : m(mod), im(-1ULL / m + 1) {} 5 | // input: a * b < 2^64, output: a * b % mod 6 | u64 mul(u64 a, u64 b) const { 7 | a *= b; 8 | u64 x = ((__uint128_t)a * im) >> 64; 9 | a -= x * m; 10 | if((ll)a < 0) a += m; 11 | return a; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /docs/string/KMP.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: KMP 法 (Knuth–Morris–Pratt algorithm) 3 | documentation_of: //src/string/KMP.hpp 4 | --- 5 | - 参考実装:[KACTL](https://github.com/kth-competitive-programming/kactl/blob/c52bac765cdd9cda1def052c698ffa7bd3318d29/content/strings/KMP.h) 6 | 7 | ## 使い方 8 | 9 | - `vector KMP(string s)`:$\text{kmp}[i] := \max\\{ l ≤ i \mid s[:l] = s[(i+1)-l:i+1] \\}$ で定義される配列 $\text{kmp}$ を求める 10 | 11 | $O(n)$ 時間 12 | -------------------------------------------------------------------------------- /src/flow/燃やす埋める.md: -------------------------------------------------------------------------------- 1 | | 変形前の制約 | 変形後の制約 | 2 | | --- | --- | 3 | | $x$ が $0$ のとき $z$ 失う | $(x, T, z)$ | 4 | | $x$ が $0$ のとき $z$ 得る | 無条件で $z$ 得る; $(S, x, z)$ | 5 | | $x$ が $1$ のとき $z$ 失う | $(S, x, z)$ | 6 | | $x$ が $1$ のとき $z$ 得る | 無条件で $z$ 得る; $(x, T, z)$ | 7 | | $x, y, \dots$ がすべて $0$ のとき $z$ 得る | 無条件で $z$ 得る; $(S, w, z), (w, x, \infty), (w, y, \infty)$ | 8 | | $x, y, \dots$ がすべて $1$ のとき $z$ 得る | 無条件で $z$ 得る; $(w, T, z), (x, w, \infty), (y, w, \infty)$ | 9 | -------------------------------------------------------------------------------- /test/string/KMP.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_14_B" 2 | #include "test/template.hpp" 3 | #include "src/string/KMP.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | string S, T; 8 | cin >> S >> T; 9 | auto s = T + '$' + S; 10 | auto kmp = KMP(s); 11 | 12 | rep(i, sz(s) - sz(S), sz(s)) { 13 | if(kmp[i] == sz(T)) cout << i - sz(T) * 2 << '\n'; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/modint/modint.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Modint 3 | documentation_of: //src/modint/modint.hpp 4 | --- 5 | - 参考実装:[AC Library (初期実装)](https://github.com/atcoder/ac-library/blob/8250de484ae0ab597391db58040a602e0dc1a419/atcoder/convolution.hpp) 6 | 7 | - タイプ速度重視の簡易 modint 8 | - 速度が欲しいとき:[32 bit で加減算をちゃんと書いた Modint](../extra/modint_fast.hpp) 9 | - mod が素数でないとき:inv を [extgcd](../math/ExtGCD.hpp) にする 10 | - mod が実行時に決まり,これを高速化したいとき:[Barrett Reduction](./BarrettReduction.hpp) 11 | -------------------------------------------------------------------------------- /src/template/template.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using ll = long long; 4 | const ll INF = LLONG_MAX / 4; 5 | #define rep(i, a, b) for(ll i = a; i < (b); i++) 6 | #define all(a) begin(a), end(a) 7 | #define sz(a) ssize(a) 8 | bool chmin(auto& a, auto b) { return a > b ? a = b, 1 : 0; } 9 | bool chmax(auto& a, auto b) { return a < b ? a = b, 1 : 0; } 10 | 11 | int main() { 12 | cin.tie(0)->sync_with_stdio(0); 13 | // your code here... 14 | } 15 | -------------------------------------------------------------------------------- /test/math/BinaryGCD.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" 2 | #include "test/template.hpp" 3 | using u64 = uint64_t; 4 | #include "src/math/BinaryGCD.hpp" 5 | 6 | int main() { 7 | mt19937_64 rnd; 8 | rep(shift, 0, 64) { 9 | rep(i, 0, (ll)1e5) { 10 | u64 a = rnd() >> shift, b = rnd() >> shift; 11 | assert(gcd(a, b) == binary_gcd(a, b)); 12 | } 13 | } 14 | puts("Hello World"); 15 | } 16 | -------------------------------------------------------------------------------- /docs/data-structure/BIT.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: BIT (Fenwick Tree) 3 | documentation_of: //src/data-structure/BIT.hpp 4 | --- 5 | 6 | - 参考実装:[AC Library](https://github.com/atcoder/ac-library/blob/8250de484ae0ab597391db58040a602e0dc1a419/atcoder/fenwicktree.hpp) 7 | 8 | ## 使い方 9 | 10 | 1 点加算・区間和ができるデータ構造 11 | 12 | - `BIT(ll n)`:長さ $n$ の配列を作る 13 | - `void add(ll i, ll x)`:`A[i] += x` を行う 14 | - `ll sum(ll r)`:`sum(A[:r])` を求める 15 | - `ll sum(ll l, ll r)`:`sum(A[l:r])` を求める 16 | 17 | 計算量 $O(\log n)$ / クエリ 18 | -------------------------------------------------------------------------------- /test/FPS/FFT.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/convolution_mod" 2 | #include "test/template.hpp" 3 | #include "src/modint/modint.hpp" 4 | #include "src/FPS/FFT.hpp" 5 | 6 | int main() { 7 | cin.tie(0)->sync_with_stdio(0); 8 | ll N, M; 9 | cin >> N >> M; 10 | vector A(N), B(M); 11 | for(mm& a : A) cin >> a.x; 12 | for(mm& b : B) cin >> b.x; 13 | 14 | auto C = conv(move(A), move(B)); 15 | rep(i, 0, sz(C)) cout << C[i].x << " \n"[i + 1 == sz(C)]; 16 | } 17 | -------------------------------------------------------------------------------- /src/data-structure/BIT.hpp: -------------------------------------------------------------------------------- 1 | struct BIT { 2 | vector a; 3 | BIT(ll n) : a(n + 1) {} 4 | void add(ll i, ll x) { // A[i] += x 5 | i++; 6 | while(i < sz(a)) { 7 | a[i] += x; 8 | i += i & -i; 9 | } 10 | } 11 | ll sum(ll r) { 12 | ll s = 0; 13 | while(r) { 14 | s += a[r]; 15 | r -= r & -r; 16 | } 17 | return s; 18 | } 19 | ll sum(ll l, ll r) { // sum of A[l, r) 20 | return sum(r) - sum(l); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /test/FPS/FFT_fast.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/convolution_mod" 2 | #include "test/template.hpp" 3 | #include "src/extra/modint_fast.hpp" 4 | #include "src/FPS/FFT_fast.hpp" 5 | 6 | int main() { 7 | cin.tie(0)->sync_with_stdio(0); 8 | ll N, M; 9 | cin >> N >> M; 10 | vector A(N), B(M); 11 | for(mm& a : A) cin >> a.x; 12 | for(mm& b : B) cin >> b.x; 13 | 14 | auto C = conv(move(A), move(B)); 15 | rep(i, 0, sz(C)) cout << C[i].x << " \n"[i + 1 == sz(C)]; 16 | } 17 | -------------------------------------------------------------------------------- /test/modint/BarrettReduction.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" 2 | #include "test/template.hpp" 3 | using u64 = uint64_t; 4 | #include "src/modint/BarrettReduction.hpp" 5 | 6 | mt19937 rnd(random_device{}()); 7 | int main() { 8 | rep(i, 0, 1e5) { 9 | const u64 mod = rnd(), a = rnd(), b = rnd(), ans1 = Barrett(mod).mul(a, b), ans2 = a * b % mod; 10 | if(mod == 0) continue; 11 | assert(ans1 == ans2); 12 | } 13 | puts("Hello World"); 14 | } 15 | -------------------------------------------------------------------------------- /docs/string/Manacher.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Manacher's algorithm 3 | documentation_of: //src/string/Manacher.hpp 4 | --- 5 | - 参考実装:[ei1333 (Luzhiled's memo)](https://ei1333.github.io/luzhiled/snippets/string/manacher.html) 6 | 7 | ## 使い方 8 | 9 | - `vector manacher(string s)`:文字列 $s$ の長さを $n$ として,長さ $n$ の整数列 $r$ を返す.$r[i]$ は $s[i]$ を中心とする回文半径で,$s[i - r[i]]$ から $s[i + r[i]]$ までが回文であることを表す. 10 | - 文字と文字の間を中心とする回文半径も知りたいときは,両端を含めた境界 ($N + 1$ 個) に適当な文字 1 種類を挿入しておく.返される値は,挿入前の文字列における回文直径${} + 1$ (すなわち,極大な回文の長さ${} + 1$) になる. 11 | 12 | $O(n)$ 時間 13 | -------------------------------------------------------------------------------- /test/string/Manacher.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/enumerate_palindromes" 2 | #include "test/template.hpp" 3 | #include "src/string/Manacher.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | string S; 8 | cin >> S; 9 | const ll N = sz(S); 10 | string T(N * 2 + 1, '$'); 11 | rep(i, 0, N) T[i * 2 + 1] = S[i]; 12 | auto r = manacher(T); 13 | rep(i, 1, N * 2) { 14 | if(i & 1) cout << r[i] - 1 << " \n"[i + 1 == N * 2]; 15 | else cout << r[i] - 1 << ' '; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/string/Manacher.hpp: -------------------------------------------------------------------------------- 1 | // 各位置での回文半径を求める 2 | // aaabaaa -> 1214121 3 | // 偶数長の回文を含めて直径を知るには,N+1 個の $ を挿入して 1 を引く 4 | // $a$a$a$b$a$a$a$ -> 123432181234321 5 | auto manacher(string s) { 6 | ll n = sz(s), i = 0, j = 0; 7 | vector r(n); 8 | while(i < n) { 9 | while(i >= j && i + j < n && s[i - j] == s[i + j]) j++; 10 | r[i] = j; 11 | ll k = 1; 12 | while(i >= k && i + k < n && k + r[i - k] < j) { 13 | r[i + k] = r[i - k]; 14 | k++; 15 | } 16 | i += k, j -= k; 17 | } 18 | return r; 19 | } 20 | -------------------------------------------------------------------------------- /test/data-structure/BIT.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/point_add_range_sum" 2 | #include "test/template.hpp" 3 | #include "src/data-structure/BIT.hpp" 4 | 5 | int main() { 6 | cin.tie(0)->sync_with_stdio(0); 7 | 8 | ll N, Q; 9 | cin >> N >> Q; 10 | 11 | BIT A(N); 12 | rep(i, 0, N) { 13 | ll a; 14 | cin >> a; 15 | A.add(i, a); 16 | } 17 | 18 | while(Q--) { 19 | ll a, b, c; 20 | cin >> a >> b >> c; 21 | if(a == 0) A.add(b, c); 22 | else cout << A.sum(b, c) << '\n'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /docs/string/Zalgorithm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Z Algorithm 3 | documentation_of: //src/string/Zalgorithm.hpp 4 | --- 5 | - 参考実装:[KACTL](https://github.com/kth-competitive-programming/kactl/blob/c52bac765cdd9cda1def052c698ffa7bd3318d29/content/strings/KMP.h) 6 | 7 | ## 使い方 8 | 9 | - `vector Z(string s)`:$Z[i] := \text{LCP}(s, s[i:])$ で定義される配列 $Z$ を求める 10 | - $O(n)$ 時間 11 | 12 | ## 使い方 (応用編) 13 | 14 | - 文字列 $s$ の部分文字列に $t$ が現れるか判定:$\text{Z}(t + s)$ の後ろ $\text{sz}(s)$ 個に $\text{sz}(t)$ 以上があるか 15 | - 文字列 $s$ の最小周期:$\text{Z}(s + s)$ の $1$ 要素目以降で,はじめて $\text{sz}(s)$ 以上が出現する位置 16 | 17 | -------------------------------------------------------------------------------- /test/string/RollingHash.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/zalgorithm" 2 | #include "test/template.hpp" 3 | using u64 = uint64_t; 4 | #include "src/string/RollingHash.hpp" 5 | 6 | int main() { 7 | cin.tie(0)->sync_with_stdio(0); 8 | string S; 9 | cin >> S; 10 | RH rh(S); 11 | const ll N = sz(S); 12 | auto LCP = [&](ll i, ll j) { 13 | ll ok = 0, ng = N + 1 - j; 14 | while(ng - ok > 1) { 15 | const ll mid = (ok + ng) / 2; 16 | (rh.get(i, i + mid) == rh.get(j, j + mid) ? ok : ng) = mid; 17 | } 18 | return ok; 19 | }; 20 | rep(i, 0, N) cout << LCP(0, i) << " \n"[i + 1 == N]; 21 | } 22 | -------------------------------------------------------------------------------- /src/string/RollingHash.hpp: -------------------------------------------------------------------------------- 1 | // using u64 = uint64_t; 2 | const u64 mod = INF; 3 | u64 add(u64 a, u64 b) { 4 | a += b; 5 | if(a >= mod) a -= mod; 6 | return a; 7 | } 8 | u64 mul(u64 a, u64 b) { 9 | auto c = (__uint128_t)a * b; 10 | return add(c >> 61, c & mod); 11 | } 12 | random_device rnd; 13 | const u64 r = ((u64)rnd() << 32 | rnd()) % mod; 14 | struct RH { 15 | ll n; 16 | vector hs, pw; 17 | RH(string s) : n(sz(s)), hs(n + 1), pw(n + 1, 1) { 18 | rep(i, 0, n) { 19 | pw[i + 1] = mul(pw[i], r); 20 | hs[i + 1] = add(mul(hs[i], r), s[i]); 21 | } 22 | } 23 | u64 get(ll l, ll r) const { return add(hs[r], mod - mul(hs[l], pw[r - l])); } 24 | }; 25 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Chromium 2 | AccessModifierOffset: -4 3 | AllowAllArgumentsOnNextLine: true 4 | AllowAllConstructorInitializersOnNextLine: true 5 | AllowAllParametersOfDeclarationOnNextLine: true 6 | AllowShortBlocksOnASingleLine: Always 7 | AllowShortCaseLabelsOnASingleLine: true 8 | AllowShortEnumsOnASingleLine: true 9 | AllowShortFunctionsOnASingleLine: All 10 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 11 | AllowShortLambdasOnASingleLine: All 12 | AllowShortLoopsOnASingleLine: true 13 | AlwaysBreakTemplateDeclarations: No 14 | BreakBeforeBinaryOperators: NonAssignment 15 | ColumnLimit: 120 16 | IndentWidth: 3 17 | IndentWrappedFunctionNames: true 18 | SpaceAfterTemplateKeyword: false 19 | SpaceBeforeParens: Never 20 | SortIncludes: Never 21 | -------------------------------------------------------------------------------- /test/benchmark/SuffixArray.cpp: -------------------------------------------------------------------------------- 1 | #include "test/template.hpp" 2 | #include "src/string/SuffixArray.hpp" 3 | // #include "atcoder/string" 4 | 5 | mt19937 rnd; 6 | int main() { 7 | using namespace chrono; 8 | const ll N = 1 << 20; 9 | string S(N, 0); 10 | rep(i, 0, N) S[i] = rnd() % 26 + 'A'; 11 | { 12 | auto s = system_clock::now(); 13 | auto [sa, lcp] = SA(S); 14 | cout << "my Suffix Array: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 15 | } 16 | { 17 | auto s = system_clock::now(); 18 | auto sa = atcoder::suffix_array(S); 19 | auto lcp = atcoder::lcp_array(S, sa); 20 | cout << "ACL: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docs/string/SuffixArray.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Suffix Array 3 | documentation_of: //src/string/SuffixArray.hpp 4 | --- 5 | - 参考実装:[kactl](https://github.com/kth-competitive-programming/kactl/blob/431a6ef4ec6c04cf4c17e065089b7c4d451ea9cf/content/strings/SuffixArray.h) 6 | 7 | ## 使い方 8 | 9 | - `pair, vector> SA(string s)`:文字列 $s$ の Suffix Array と LCP Array の組を返す. 10 | - Suffix Array:`[0, 1, …, n-1].sort(key=(i => s[i:]))` 11 | - LCP Array:`lcp[i] = LCP(s[sa[i]:], s[sa[i+1]:])` 12 | - `lim` には $s$ の文字種の最大値を指定する 13 | - $O(n \log n)$ 時間 14 | 15 | ## ベンチマーク 16 | 17 | | $n = 2^{20}$ の SA + LCP | 所要時間 | 18 | | --- | --- | 19 | | これ | 310 ms | 20 | | [AC Library](https://github.com/atcoder/ac-library/blob/d8ca7f26686f6c78d15d13ca438ea866526e87fb/atcoder/string.hpp) | 100 ms | 21 | -------------------------------------------------------------------------------- /test/data-structure/FastSet.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.yosupo.jp/problem/predecessor_problem" 2 | #include "test/template.hpp" 3 | using u64 = uint64_t; 4 | #include "src/data-structure/FastSet.hpp" 5 | 6 | int main() { 7 | cin.tie(0)->sync_with_stdio(0); 8 | ll N, Q; 9 | cin >> N >> Q; 10 | string S; 11 | cin >> S; 12 | FastSet s(N); 13 | rep(i, 0, N) if(S[i] == '1') s.set(i); 14 | while(Q--) { 15 | ll c, k; 16 | cin >> c >> k; 17 | if(c == 0) s.set(k); 18 | if(c == 1) s.reset(k); 19 | if(c == 2) cout << (s.a[0][k / B] >> (k % B) & 1) << '\n'; 20 | if(c == 3) { 21 | ll ans = s.next(k - 1); 22 | cout << (ans == N ? -1 : ans) << '\n'; 23 | } 24 | if(c == 4) cout << s.prev(k + 1) << '\n'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/modint/BarrettReduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Barrett Reduction 3 | documentation_of: //src/modint/BarrettReduction.hpp 4 | --- 5 | - 参考実装:[AC Library](https://github.com/atcoder/ac-library/blob/master/atcoder/internal_math.hpp) 6 | 7 | 同じ mod でたくさん計算するとき,剰余算を掛け算に変換して高速化する. 8 | 9 | ## 使い方 10 | 11 | - `Barrett br(mod)`:Barrett Reduction を準備する. 12 | - 制約:`mod < 2^32` 13 | - `u64 br.mul(u64 a, u64 b)`:`a * b % mod` を計算する. 14 | - 制約:`a * b < 2^64` 15 | 16 | ## 仕組み 17 | 18 | - 整数部 64 bit,小数部 64 bit の固定小数点数で商を計算する. 19 | - `im` には `1.0 / mod` の小数部 64 bit が書かれている. 20 | - `u64 x = ((__uint128_t)a * im) >> 64;` で商を計算している. 21 | 22 | ## 余談 23 | 24 | ジャッジが Ice Lake より前の Intel の CPU の場合,64 bit 除算が double 除算より 3 倍以上遅いことが知られている. 25 | あまりではなく商が欲しい場合,mod が固定ではない場合,もっと短く書きたい場合は,double 除算や long double 除算を書くと良い. 26 | -------------------------------------------------------------------------------- /test/modint/modint.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" 2 | #include "test/template.hpp" 3 | #include "src/modint/modint.hpp" 4 | 5 | mt19937 rnd(random_device{}()); 6 | int main() { 7 | rep(i, 0, 1e5) { 8 | const ll a = rnd() % mod, b = rnd() % mod; 9 | mm A = a, B = b, C = A * B; 10 | assert((A + B).x == (a + b) % mod); 11 | assert((A - B).x == (a - b + mod) % mod); 12 | assert(C.x == (a * b) % mod); 13 | assert((A / B.inv()).x == C.x); 14 | A = a; 15 | assert((A += B).x == (a + b) % mod); 16 | A = a; 17 | assert((A -= B).x == (a - b + mod) % mod); 18 | A = a; 19 | assert((A *= B).x == (a * b) % mod); 20 | A = a; 21 | assert((A /= B.inv()).x == C.x); 22 | } 23 | puts("Hello World"); 24 | } 25 | -------------------------------------------------------------------------------- /test/math/ExtGCD.test.cpp: -------------------------------------------------------------------------------- 1 | #define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" 2 | #include "test/template.hpp" 3 | #include "src/math/ExtGCD.hpp" 4 | 5 | using i128 = __int128_t; 6 | i128 abs(i128 x) { return x < 0 ? -x : x; } 7 | int main() { 8 | mt19937_64 rnd; 9 | rep(shift, 1, 64) { 10 | rep(i, 0, (ll)5e4) { 11 | ll a = rnd() >> shift; 12 | ll b = rnd() >> shift; 13 | const ll g = gcd(a, b); 14 | ll x, y; 15 | assert(extgcd(a, b, x, y) == g); 16 | assert((i128)a * x + (i128)b * y == g); 17 | if(g) { 18 | assert(abs((i128)x) + abs((i128)y) <= abs((i128)x - b / g) + abs((i128)y + a / g)); 19 | assert(abs((i128)x) + abs((i128)y) <= abs((i128)x + b / g) + abs((i128)y - a / g)); 20 | } 21 | } 22 | } 23 | puts("Hello World"); 24 | } 25 | -------------------------------------------------------------------------------- /docs/math/ExtGCD.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 拡張ユークリッドの互除法 (Extended Euclidean algorithm) 3 | documentation_of: //src/math/ExtGCD.hpp 4 | --- 5 | - 参考実装:[KACTL](https://github.com/kth-competitive-programming/kactl/blob/main/content/number-theory/euclid.h) 6 | 7 | ## 使い方 8 | 9 | - `ll extgcd(ll a, ll b, ll& x, ll& y)`:$\text{gcd}(a, b)$ を返す.$(x, y)$ には,$ax + by = \text{gcd}(a, b)$ の整数解であって $\|x\| + \|y\|$ が最小のものが代入される. 10 | - $O(\log(x + y))$ 時間 11 | 12 | ## 使い方 (応用) 13 | 14 | - モジュロ逆元 `modinv(a, mod)` を求める:`extgcd(a, mod, x, y)` をすると `a * x + mod * y == 1` になるので,`x` が `a` のモジュロ逆元である. 15 | 16 | ## ソラ書きしてみよう 17 | 18 | $(1, 0, a)$ と $(0, 1, b)$ に対してユークリッドの互除法をするとできる. 19 | 20 | ```cpp 21 | array extgcd(ll a, ll b) { 22 | array A = {1, 0, a}, B = {0, 1, b}; 23 | while(B[2]) { 24 | ll q = A[2] / B[2]; 25 | rep(i, 0, 3) A[i] -= B[i] * q; 26 | swap(A, B); 27 | } 28 | return A; 29 | } 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /src/modint/modint.hpp: -------------------------------------------------------------------------------- 1 | const ll mod = 998244353; 2 | struct mm { 3 | ll x; 4 | mm(ll x_ = 0) : x(x_ % mod) { 5 | if(x < 0) x += mod; 6 | } 7 | friend mm operator+(mm a, mm b) { return a.x + b.x; } 8 | friend mm operator-(mm a, mm b) { return a.x - b.x; } 9 | friend mm operator*(mm a, mm b) { return a.x * b.x; } 10 | friend mm operator/(mm a, mm b) { return a * b.inv(); } 11 | // 4 行コピペ Alt + Shift + クリックで複数カーソル 12 | friend mm& operator+=(mm& a, mm b) { return a = a.x + b.x; } 13 | friend mm& operator-=(mm& a, mm b) { return a = a.x - b.x; } 14 | friend mm& operator*=(mm& a, mm b) { return a = a.x * b.x; } 15 | friend mm& operator/=(mm& a, mm b) { return a = a * b.inv(); } 16 | mm inv() const { return pow(mod - 2); } 17 | mm pow(ll b) const { 18 | mm a = *this, c = 1; 19 | while(b) { 20 | if(b & 1) c *= a; 21 | a *= a; 22 | b >>= 1; 23 | } 24 | return c; 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /.verify-helper/timestamps.remote.json: -------------------------------------------------------------------------------- 1 | { 2 | "test/FPS/FFT.test.cpp": "2024-05-31 19:00:40 +0900", 3 | "test/FPS/FFT_fast.test.cpp": "2024-05-31 19:00:40 +0900", 4 | "test/data-structure/BIT.test.cpp": "2024-05-31 19:00:40 +0900", 5 | "test/data-structure/FastSet.test.cpp": "2024-05-31 19:00:40 +0900", 6 | "test/math/BinaryGCD.test.cpp": "2024-06-01 01:21:46 +0900", 7 | "test/math/ExtGCD.test.cpp": "2024-06-01 10:05:24 +0900", 8 | "test/modint/BarrettReduction.test.cpp": "2024-05-31 19:00:40 +0900", 9 | "test/modint/modint.test.cpp": "2024-05-31 19:00:40 +0900", 10 | "test/string/KMP.test.cpp": "2024-05-31 19:00:40 +0900", 11 | "test/string/LCP.test.cpp": "2024-05-31 19:00:40 +0900", 12 | "test/string/Manacher.test.cpp": "2024-05-31 19:00:40 +0900", 13 | "test/string/RollingHash.test.cpp": "2024-05-31 19:00:40 +0900", 14 | "test/string/SuffixArray.test.cpp": "2024-05-31 19:00:40 +0900", 15 | "test/string/Zalgorithm.test.cpp": "2024-05-31 19:00:40 +0900", 16 | "test/template.test.cpp": "2024-05-31 23:58:41 +0900" 17 | } -------------------------------------------------------------------------------- /docs/FPS/FFT_fast.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FFT (bit reversal ver.) 3 | documentation_of: //src/FPS/FFT_fast.hpp 4 | --- 5 | - 参考実装:[AC Library (初期実装)](https://github.com/atcoder/ac-library/blob/8250de484ae0ab597391db58040a602e0dc1a419/atcoder/convolution.hpp) 6 | 7 | ## Depends on 8 | 9 | - [Modint](../modint/modint.hpp) 10 | 11 | より高速な FFT.4 進でやるとより高速になるが,長すぎるので妥協 12 | 13 | ## 使い方 14 | 15 | - `void fft(vector& a)`:長さが $n$ : $2$ べきの数列 $a$ の離散フーリエ変換を行う 16 | - **`fft()` 後の配列は bit reversal 順になっていることに注意.**例えば $n = 16$ のとき,$(0101)_2 = 5$ の bit 順を反転させると $(1010)_2 = 10$ であるから,$f(\omega^5)$ の値は $a[10]$ に入っている. 17 | - `void ifft(vector& a)`:`fft()` の逆変換を行う 18 | - `vector conv(vector a, vector b)`:数列 $a, b$ の畳み込みを行う 19 | - $c[k] := \sum_{i + j = k}a[i] \times b[j]$ で定義される,長さ $\text{sz}(a) + \text{sz}(b) - 1$ の数列 $c$ を返す. 20 | 21 | $O(n \log n)$ 時間 22 | 23 | ## 注意 24 | 25 | - `fft()`, `ifft()` の入力は長さが 2 べきであること 26 | - FFT 後の配列は bit reversal 順に並ぶ 27 | - FFT → IFFT をすると各要素が $n$ 倍されるので、$n$ で割る必要がある 28 | -------------------------------------------------------------------------------- /src/FPS/FFT.hpp: -------------------------------------------------------------------------------- 1 | // {998244353, 3}, {1811939329, 13}, {2013265921, 31} 2 | mm g = 3; // 原始根 3 | void fft(vector& a) { 4 | ll n = sz(a), lg = __lg(n); 5 | assert((1 << lg) == n); 6 | vector b(n); 7 | rep(l, 1, lg + 1) { 8 | ll w = n >> l; 9 | mm s = 1, r = g.pow(mod >> l); 10 | for(ll u = 0; u < n / 2; u += w) { 11 | rep(d, 0, w) { 12 | mm x = a[u << 1 | d], y = a[u << 1 | w | d] * s; 13 | b[u | d] = x + y; 14 | b[n >> 1 | u | d] = x - y; 15 | } 16 | s *= r; 17 | } 18 | swap(a, b); 19 | } 20 | } 21 | vector conv(vector a, vector b) { 22 | if(a.empty() || b.empty()) return {}; 23 | size_t s = sz(a) + sz(b) - 1, n = bit_ceil(s); 24 | // if(min(sz(a), sz(b)) <= 60) 愚直に掛け算 25 | a.resize(n); 26 | b.resize(n); 27 | fft(a); 28 | fft(b); 29 | mm inv = mm(n).inv(); 30 | rep(i, 0, n) a[i] *= b[i] * inv; 31 | reverse(1 + all(a)); 32 | fft(a); 33 | a.resize(s); 34 | return a; 35 | } 36 | -------------------------------------------------------------------------------- /docs/data-structure/FastSet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 高速 bitset (64 分木) 3 | documentation_of: //src/data-structure/FastSet.hpp 4 | --- 5 | 6 | - 参考実装:[Gifted Infants](https://yosupo.hatenablog.com/entry/2019/07/02/122433) 7 | 8 | ## 使い方 9 | 10 | 整数の set を高速化したい時に使う 11 | 12 | - `FastSet(ll n)`:長さ $n$ の bitset を作る 13 | - `void set(ll i)`:`A[i] = true` を行う 14 | - `void reset(ll i)`:`A[i] = false` を行う 15 | - `ll next(ll i)`:$i$ を超える最小の要素を求める 16 | - std::set における `A.upper_bound(i)` に相当 17 | - std::bitset における `A._Find_next(i)` に相当 18 | - `ll prev(ll i)`:$i$ より小さい最大の要素を求める 19 | - std::set における `prev(A.lower_bound(i))` に相当 20 | 21 | 時間計算量 $O(\log_{\text{word}} n)$ / クエリ 22 | 空間計算量 $(\frac{\text{word}}{\text{word} - 1}\cdot n + O(\log_{\text{word}} n))$ bits  ($\boldsymbol{n}$ bits くらいのメモリを使います) 23 | 24 | ## ベンチマーク 25 | 26 | 値域 $2^{30}$ 27 | 28 | | $n = 2^{20}$ 回の 追加 + next クエリ | 所要時間 | 29 | | std::set | 467 ms | 30 | | std::bitset | 254 ms | 31 | | FastSet | 56 ms | 32 | 33 | 脅威の 8 倍速! 34 | -------------------------------------------------------------------------------- /docs/string/RollingHash.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rolling Hash 3 | documentation_of: //src/string/RollingHash.hpp 4 | --- 5 | - 参考実装:[tatyam](https://github.com/tatyam-prime/kyopro_library/blob/master/RollingHash.cpp) 6 | 7 | ## 使い方 8 | 9 | - `RH rh(string s)`:文字列 $s$ に対する Rolling Hash を準備する 10 | - $O(n)$ 時間 11 | - `u64 rh.get(ll l, ll r)`:$s[l:r]$ の hash を求める 12 | - mod を $P := 2^{61}-1$ とし,基数 $r$ を $[0, P)$ からランダムに選ぶ 13 | - このとき,長さ $n$ の文字列 $s$ の hash は $(s[0] r^{n-1} + s[1] r^{n-2} + \dots + s[n-1] r^0) \bmod P$ で計算される 14 | - $O(1)$ 時間 15 | 16 | ## 使い方 (応用編) 17 | 18 | - LCP (Longest Common Prefix) を求めたいとき:LCP の長さを二分探索すれば,$O(\log n)$ 時間 / query 19 | - 文字列を辞書順で比較したいとき:LCP の長さを二分探索すれば,$O(\log n)$ 時間 / query 20 | 21 | ## 衝突確率 22 | 23 | - $2$ つの異なる長さ $n$ 以下の文字列が衝突する確率は $\frac{n}{P}$ 以下 24 | - 参考資料:[Schwartz–Zippel lemma による hash の解析 – noshi91](https://github.com/noshi91/blog/blob/master/pages/hash.pdf) 25 | - 相異なる $n$ 文字の文字列 $m$ 個がどこかで衝突する確率は,$\frac{n \cdot \binom{m}{2}}{P}$ 以下 26 | - $(n, m) = (1, 10^6)$ を $100$ ケースやっても $0.002\%$ なので,衝突は基本的に無視できる 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PHONY: build verify serve 2 | 3 | build: notebook.pdf 4 | 5 | verify: .verify-helper/timestamps.local.json $(wildcard src/*/* test/* test/*/*) 6 | clang-format -i test/*/*.cpp test/*.hpp 7 | oj-verify run 8 | 9 | URL = "http://127.0.0.1:4000" 10 | 11 | serve: build verify 12 | cp notebook.pdf .verify-helper/docs/static/ 13 | cp build/notebook.html .verify-helper/docs/static/ 14 | cp build/*.css .verify-helper/docs/static/ 15 | oj-verify docs 16 | cd .verify-helper/markdown; \ 17 | bundle install; \ 18 | ( sleep 5.5; \ 19 | ( command -v open && open $(URL) ) || \ 20 | ( command -v start && start $(URL) ) || \ 21 | xdg-open $(URL) ) & \ 22 | bundle exec jekyll serve --incremental 23 | 24 | notebook.pdf: build/base.css build/notebook.css build/notebook.html 25 | vivliostyle build build/notebook.html -o notebook.pdf 26 | 27 | build/notebook.html: build/build.js $(wildcard src/*/* src/*/*/*) .clang-format 28 | clang-format -i $(wildcard src/*/*.hpp src/*/*/*.hpp) 29 | node build/build.js 30 | 31 | build/notebook.css: build/build.js 32 | node build/build.js 33 | -------------------------------------------------------------------------------- /src/extra/modint_fast.hpp: -------------------------------------------------------------------------------- 1 | const uint32_t mod = 998244353; 2 | struct mm { 3 | uint32_t x; 4 | mm() : x(0) {} 5 | template mm(T x_) : x(x_ % mod) { 6 | if(x >= mod) x += mod; 7 | } 8 | friend mm operator+(mm a, mm b) { 9 | a.x += b.x; 10 | if(a.x >= mod) a.x -= mod; 11 | return a; 12 | } 13 | friend mm operator-(mm a, mm b) { 14 | a.x -= b.x; 15 | if(a.x >= mod) a.x += mod; 16 | return a; 17 | } 18 | friend mm operator*(mm a, mm b) { return (uint64_t)a.x * b.x; } 19 | friend mm operator/(mm a, mm b) { return a * b.inv(); } 20 | friend mm& operator+=(mm& a, mm b) { return a = a + b; } 21 | friend mm& operator-=(mm& a, mm b) { return a = a - b; } 22 | friend mm& operator*=(mm& a, mm b) { return a = a * b; } 23 | friend mm& operator/=(mm& a, mm b) { return a = a * b.inv(); } 24 | mm inv() const { return pow(mod - 2); } 25 | mm pow(ll b) const { 26 | mm a = *this, c = 1; 27 | while(b) { 28 | if(b & 1) c *= a; 29 | a *= a; 30 | b >>= 1; 31 | } 32 | return c; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/string/SuffixArray.hpp: -------------------------------------------------------------------------------- 1 | // returns pair{sa, lcp} 2 | // sa 長さ n : s[sa[0]:] < s[sa[1]:] < … < s[sa[n-1]:] 3 | // lcp 長さ n-1 : lcp[i] = LCP(s[sa[i]:], s[sa[i+1]:]) 4 | auto SA(string s) { 5 | ll n = sz(s) + 1, lim = 256; 6 | // assert(lim > ranges::max(s)); 7 | vector sa(n), lcp(n), x(all(s) + 1), y(n), ws(max(n, lim)), rk(n); 8 | iota(all(sa), 0); 9 | for(ll j = 0, p = 0; p < n; j = max(1LL, j * 2), lim = p) { 10 | p = j; 11 | iota(all(y), n - j); 12 | rep(i, 0, n) if(sa[i] >= j) y[p++] = sa[i] - j; 13 | fill(all(ws), 0); 14 | rep(i, 0, n) ws[x[i]]++; 15 | rep(i, 1, lim) ws[i] += ws[i - 1]; 16 | for(ll i = n; i--;) sa[--ws[x[y[i]]]] = y[i]; 17 | swap(x, y); 18 | p = 1; 19 | x[sa[0]] = 0; 20 | rep(i, 1, n) { 21 | ll a = sa[i - 1], b = sa[i]; 22 | x[b] = (y[a] == y[b] && y[a + j] == y[b + j]) ? p - 1 : p++; 23 | } 24 | } 25 | rep(i, 1, n) rk[sa[i]] = i; 26 | for(ll i = 0, k = 0; i < n - 1; lcp[rk[i++]] = k) { 27 | if(k) k--; 28 | while(s[i + k] == s[sa[rk[i] - 1] + k]) k++; 29 | } 30 | sa.erase(begin(sa)); 31 | lcp.erase(begin(lcp)); 32 | return pair{sa, lcp}; 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /src/memo/Primes.md: -------------------------------------------------------------------------------- 1 | #### 素数の個数 2 | 3 | | $n$ | $10^2$ | $10^3$ | $10^4$ | $10^5$ | $10^6$ | $10^7$ | $10^8$ | $10^9$ | $10^{10}$ | 4 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 5 | | $\pi(n)$ | 25 | 168 | 1229 | 9592 | 78498 | 664579 | 5.76e+6 | 5.08e+7 | 4.55e+8 | 6 | 7 | #### 高度合成数 8 | 9 | | $≤n$ | $10^3$ | $10^4$ | $10^5$ | $10^6$ | $10^7$ | $10^8$ | $10^9$ | 10 | | --- | --- | --- | --- | --- | --- | --- | --- | 11 | | $x$ | 840 | 7560 | 83160 | 720720 | 8648640 | 73513440 | 735134400 | 12 | | $d^0(x)$ | 32 | 64 | 128 | 240 | 448 | 768 | 1344 | 13 | 14 | | $≤n$ | $10^{10}$ | $10^{11}$ | $10^{12}$ | $10^{13}$ | $10^{14}$ | $10^{15}$ | $10^{16}$ | $10^{17}$ | $10^{18}$ | 15 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 16 | | $d^0(x)$ | 2304 | 4032 | 6720 | 10752 | 17280 | 26880 | 41472 | 64512 | 103680 | 17 | 18 | #### 素数階乗 19 | 20 | | $n$ | $2$ | $3$ | $5$ | $7$ | $11$ | $13$ | $17$ | $19$ | $23$ | $29$ | 21 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 22 | | $n\\#$ | 2 | 6 | 30 | 210 | 2310 | 30030 | 510510 | 9.70e+6 | 2.23e+8 | 6.47e+9 | 23 | 24 | #### 階乗 25 | 26 | | $4!$ | $5!$ | $6!$ | $7!$ | $8!$ | $9!$ | $10!$ | $11!$ | $12!$ | $13!$ | 27 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 28 | | 24 | 120 | 720 | 5040 | 40320 | 362880 | 3.63e+6 | 3.99e+7 | 4.79e+8 | 6.23e+9 | 29 | -------------------------------------------------------------------------------- /src/data-structure/FastSet.hpp: -------------------------------------------------------------------------------- 1 | // using u64 = uint64_t; 2 | const u64 B = 64; 3 | struct FastSet { 4 | u64 n; 5 | vector> a; 6 | FastSet(u64 n_) : n(n_) { 7 | do a.emplace_back(n_ = (n_ + B - 1) / B); 8 | while(n_ > 1); 9 | } 10 | // bool operator[](ll i) const { return a[0][i / B] >> (i % B) & 1; } 11 | void set(ll i) { 12 | for(auto& v : a) { 13 | v[i / B] |= 1ULL << (i % B); 14 | i /= B; 15 | } 16 | } 17 | void reset(ll i) { 18 | for(auto& v : a) { 19 | v[i / B] &= ~(1ULL << (i % B)); 20 | if(v[i / B]) break; 21 | i /= B; 22 | } 23 | } 24 | ll next(ll i) { // i を超える最⼩の要素 25 | rep(h, 0, sz(a)) { 26 | i++; 27 | if(i / B >= sz(a[h])) break; 28 | u64 d = a[h][i / B] >> (i % B); 29 | if(d) { 30 | i += countr_zero(d); 31 | while(h--) i = i * B + countr_zero(a[h][i]); 32 | return i; 33 | } 34 | i /= B; 35 | } 36 | return n; 37 | } 38 | ll prev(ll i) { // i より小さい最⼤の要素 39 | rep(h, 0, sz(a)) { 40 | i--; 41 | if(i < 0) break; 42 | u64 d = a[h][i / B] << (~i % B); 43 | if(d) { 44 | i -= countl_zero(d); 45 | while(h--) i = i * B + __lg(a[h][i]); 46 | return i; 47 | } 48 | i /= B; 49 | } 50 | return -1; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /test/benchmark/FastSet.cpp: -------------------------------------------------------------------------------- 1 | #include "test/template.hpp" 2 | using u64 = uint64_t; 3 | #include "src/data-structure/FastSet.hpp" 4 | 5 | mt19937 rnd; 6 | int main() { 7 | auto test = [&](const vector& query, const string& name, auto add, auto next) { 8 | using namespace chrono; 9 | ll ans = 0; 10 | auto s = system_clock::now(); 11 | for(ll x : query) { 12 | add(x); 13 | ans += next(x); 14 | } 15 | cout << name << ": " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 16 | cerr << ans << endl; 17 | }; 18 | 19 | const ll N = 1 << 21; 20 | const ll MAX = 1 << 30; 21 | cout << "N = " << N << ", MAX = " << MAX << endl; 22 | vector query(N); 23 | rep(i, 0, N) query[i] = rnd() >> 2; 24 | shuffle(all(query), rnd); 25 | { 26 | std::set s; 27 | test( 28 | query, "std::set", [&](ll x) { s.insert(x); }, 29 | [&](ll x) -> ll { 30 | auto p = s.upper_bound(x); 31 | if(p == end(s)) return MAX; 32 | return *p; 33 | }); 34 | } 35 | { 36 | static bitset s; 37 | test( 38 | query, "std::bitset", [&](ll x) { s[x] = 1; }, [&](ll x) { return s._Find_next(x); }); 39 | } 40 | { 41 | FastSet s(MAX); 42 | test( 43 | query, "FastSet", [&](ll x) { s.set(x); }, [&](ll x) { return s.next(x); }); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/FPS/FFT.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: FFT (高速フーリエ変換 / 畳み込み) 3 | documentation_of: //src/FPS/FFT.hpp 4 | --- 5 | - 参考実装:[gifted infants](https://yosupo.hatenablog.com/entry/2019/07/02/122433) 6 | 7 | ## Depends on 8 | 9 | - [Modint](../modint/modint.hpp) 10 | 11 | ## 使い方 12 | 13 | - `void fft(vector& a)`:長さが $n$ : $2$ べきの数列 $a$ の離散フーリエ変換を行う. 14 | - $f(x) := a[0] + a[1]x + \dots + a[n - 1]x^{n - 1},\ \omega := e^{i\frac{\tau}{n}}$ としたとき,列 $[f(\omega^0), f(\omega^1), \dots, f(\omega^{n-1})]$ を返す. 15 | - **bit reversal 順ではないことに注意** 16 | - `vector conv(vector a, vector b)`:数列 $a, b$ の畳み込みを行う. 17 | - $c[k] := \sum_{i + j = k}a[i] \times b[j]$ で定義される,長さ $\text{sz}(a) + \text{sz}(b) - 1$ の数列 $c$ を返す. 18 | 19 | $O(n \log n)$ 時間 20 | 21 | ## 注意 22 | 23 | - `fft()` の入力は長さが 2 べきであること 24 | - **IFFT は,FFT における $[\omega^1, \dots, \omega^{n-1}]$ を $[\omega^{n-1}, \dots, \omega^{1}]$ で置き換えたものなので,FFT の結果の $[f(\omega^1), \dots, f(\omega^{n-1})]$ の部分を reverse すれば良い.出力を reverse する代わりに,入力の同じ部分を reverse しても良い.** 25 | - FFT → IFFT をすると各要素が $n$ 倍されるので、$n$ で割る必要がある 26 | 27 | ## ベンチマーク 28 | 29 | | $2^{20} + 2^{20}$ の畳み込み | 所要時間 | 30 | | --- | --- | 31 | | [簡易 modint](../modint/modint.hpp) + 簡易 FFT (これ) | 300 ms | 32 | | [32 bit で加減算をちゃんと書いた modint](../extra/modint_fast.hpp) + [bit reversal FFT](FFT_fast.hpp) | 123 ms | 33 | | [AC Library](https://github.com/atcoder/ac-library/blob/d8ca7f26686f6c78d15d13ca438ea866526e87fb/atcoder/convolution.hpp) | 79 ms | 34 | | [Nyaan さんの AVX2 FFT](https://nyaannyaan.github.io/library/verify/verify-yosupo-ntt/yosupo-convolution-ntt-avx2.test.cpp) | 43 ms | 35 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify library & Generate documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | verify: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: '3.x' 26 | cache: 'pip' 27 | 28 | - name: Install dependencies 29 | run: | 30 | pip install -U pip 31 | pip install -r requirements.txt 32 | 33 | - run: oj-verify all 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | GH_PAT: this_token_is_never_used_but_oj_verify_requires_this 37 | 38 | - run: git switch main 39 | 40 | - name: Set up Node.js 41 | uses: actions/setup-node@v4 42 | with: 43 | node-version: 'latest' 44 | cache: 'npm' 45 | 46 | - name: Install Vivliostyle 47 | run: npm install -g @vivliostyle/cli clang-format 48 | 49 | - name: Install dependencies 50 | run: npm install 51 | 52 | - name: Build PDF 53 | run: make build 54 | 55 | - name: commit PDF 56 | run: git add . && git commit -m "[skip actions] build PDF" && git push 57 | 58 | - name: copy to gh-pages 59 | run: | 60 | DIR=$(mktemp -d) 61 | cp notebook.pdf $DIR 62 | cp build/*.css $DIR 63 | cp build/*.html $DIR 64 | git clean -dfx 65 | git switch gh-pages 66 | cp $DIR/* . 67 | git add . && git commit -m "build PDF" && git push 68 | git switch main 69 | -------------------------------------------------------------------------------- /src/FPS/FFT_fast.hpp: -------------------------------------------------------------------------------- 1 | // modint を u32 にして加減算を真面目にやると速い 2 | mm g = 3; // 原始根 3 | void fft(vector& a) { 4 | ll n = sz(a), lg = __lg(n); 5 | static auto z = [] { 6 | vector z(30); 7 | mm s = 1; 8 | rep(i, 2, 32) { 9 | z[i - 2] = s * g.pow(mod >> i); 10 | s *= g.inv().pow(mod >> i); 11 | } 12 | return z; 13 | }(); 14 | rep(l, 0, lg) { 15 | ll w = 1 << (lg - l - 1); 16 | mm s = 1; 17 | rep(k, 0, 1 << l) { 18 | ll o = k << (lg - l); 19 | rep(i, o, o + w) { 20 | mm x = a[i], y = a[i + w] * s; 21 | a[i] = x + y; 22 | a[i + w] = x - y; 23 | } 24 | s *= z[countr_zero(~k)]; 25 | } 26 | } 27 | } 28 | // コピペ 29 | void ifft(vector& a) { 30 | ll n = sz(a), lg = __lg(n); 31 | static auto z = [] { 32 | vector z(30); 33 | mm s = 1; 34 | rep(i, 2, 32) { // g を逆数に 35 | z[i - 2] = s * g.inv().pow(mod >> i); 36 | s *= g.pow(mod >> i); 37 | } 38 | return z; 39 | }(); 40 | for(ll l = lg; l--;) { // 逆順に 41 | ll w = 1 << (lg - l - 1); 42 | mm s = 1; 43 | rep(k, 0, 1 << l) { 44 | ll o = k << (lg - l); 45 | rep(i, o, o + w) { 46 | mm x = a[i], y = a[i + w]; // *s を下に移動 47 | a[i] = x + y; 48 | a[i + w] = (x - y) * s; 49 | } 50 | s *= z[countr_zero(~k)]; 51 | } 52 | } 53 | } 54 | vector conv(vector a, vector b) { 55 | if(a.empty() || b.empty()) return {}; 56 | size_t s = sz(a) + sz(b) - 1, n = bit_ceil(s); 57 | // if(min(sz(a), sz(b)) <= 60) 愚直に掛け算 58 | a.resize(n); 59 | b.resize(n); 60 | fft(a); 61 | fft(b); 62 | mm inv = mm(n).inv(); 63 | rep(i, 0, n) a[i] *= b[i] * inv; 64 | ifft(a); 65 | a.resize(s); 66 | return a; 67 | } 68 | -------------------------------------------------------------------------------- /test/benchmark/FFT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | namespace nyaan { 6 | 7 | // ここにライブラリを貼る 8 | 9 | } // namespace nyaan 10 | // #include "atcoder/convolution" 11 | 12 | #include "test/template.hpp" 13 | 14 | namespace fft1 { 15 | #include "src/modint/modint.hpp" 16 | #include "src/FPS/FFT.hpp" 17 | } // namespace fft1 18 | namespace fft2 { 19 | #include "src/extra/modint_fast.hpp" 20 | #include "src/FPS/FFT_fast.hpp" 21 | } // namespace fft2 22 | 23 | int main() { 24 | using namespace chrono; 25 | const ll N = 1 << 20; 26 | { 27 | vector A(N), B(N); 28 | rep(i, 0, N) A[i] = B[i] = i; 29 | auto s = system_clock::now(); 30 | auto C = fft1::conv(A, B); 31 | cout << "my FFT: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 32 | } 33 | { 34 | vector A(N), B(N); 35 | rep(i, 0, N) A[i] = B[i] = i; 36 | auto s = system_clock::now(); 37 | auto C = fft2::conv(A, B); 38 | cout << "my fast FFT: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 39 | } 40 | { 41 | vector A(N), B(N); 42 | rep(i, 0, N) A[i] = B[i] = i; 43 | auto s = system_clock::now(); 44 | auto C = atcoder::convolution(A, B); 45 | cout << "ACL: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 46 | } 47 | { 48 | const int MOD = 998244353; 49 | using mint = nyaan::LazyMontgomeryModInt; 50 | nyaan::NTT ntt; 51 | vector A(N), B(N); 52 | rep(i, 0, N) A[i] = B[i] = i; 53 | auto s = system_clock::now(); 54 | auto C = ntt.multiply(A, B); 55 | cout << "nyaan AVX2: " << duration_cast(system_clock::now() - s).count() << " ms" << endl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ICPC_notebook 2 | 3 | [![Actions Status](https://github.com/tatyam-prime/ICPC_notebook/workflows/verify/badge.svg)](https://github.com/tatyam-prime/ICPC_notebook/actions) [![GitHub Pages](https://img.shields.io/static/v1?label=GitHub+Pages&message=document+&color=brightgreen&logo=github)](https://tatyam-prime.github.io/ICPC_notebook/) 4 | 5 | - CSS 組版で、ファイルを置くだけで PDF が簡単に作れる、ICPC 用ライブラリのすごいテンプレート 6 | - かつ、みんなでつくる最強の ICPC 用ライブラリ (予定) 7 | - [ライブラリのドキュメント](https://tatyam-prime.github.io/ICPC_notebook/) 8 | - [ライブラリをまとめたページ](https://tatyam-prime.github.io/ICPC_notebook/notebook.html) 9 | - [ライブラリをまとめた PDF](https://tatyam-prime.github.io/ICPC_notebook/notebook.pdf) 10 | 11 | ## private なコピーを作るには 12 | 13 | 1. 新規 private repository を作る 14 | 2. repository の Settings -> Actions -> Workflow permissions を Read and Write に設定 15 | 3. `git clone https://github.com/tatyam-prime/ICPC_notebook.git && cd ICPC_notebook` 16 | 4. `git remote set-url origin {your_private_repository_url}` 17 | 5. `git commit -m "test" --allow-empty && git push` 18 | 6. workflow が動くことを確認 19 | 7. [README.md](README.md) をいい感じに修正 20 | 21 | ## 内容を変更するには 22 | 23 | 1. [src/\*/\*](src/) の中身を変更する 24 | 2. [build/build.js](build/build.js) の設定項目を変更する 25 | 3. commit & push 26 | 27 | ### その他 28 | 29 | - [Makefile](Makefile) で clang-format による自動フォーマットを行っています.フォーマットの設定は [.clang-format](.clang-format) で変更できます. 30 | 31 | ## 手元で動かすには 32 | 33 | ### 事前にインストールするもの 34 | 35 | - node.js (v18 以上) 36 | - npm 37 | - `brew install node` / 38 | - clang-format 39 | - `brew install clang-format` / `sudo apt install clang-format` 40 | - vivliostyle 41 | - `npm install -g @vivliostyle/cli` 42 | - その他依存関係 43 | - `npm install` 44 | - (使うなら) oj-verify 45 | - `pip3 install online-judge-verify-helper` 46 | 47 | ### PDF を生成する 48 | 49 | 1. `make build` 50 | 51 | ### oj-verify で verify 52 | 53 | 1. `make verify` 54 | 55 | ### oj-verify ページを生成 56 | 57 | 1. `make serve` 58 | 59 | --------------------------------------------------------------------------------