├── README.md ├── _TODO_cleanup ├── linear_function.md ├── linkcut.md ├── modint.md └── z_algo.md ├── cpp ├── _doc │ ├── ds_cartesian_tree.md │ ├── ds_count_distinct.md │ ├── ds_fenwick.md │ ├── ds_fenwick2d.md │ ├── ds_range_sum.md │ ├── etc_max_sumarray.md │ ├── geometry_point.md │ ├── geometry_polar_sort.md │ ├── graph_dinic.md │ ├── graph_mcmf.md │ ├── graph_scc.md │ ├── math_euler_phi.md │ ├── math_fft.md │ ├── math_floor_sum.md │ ├── math_harmonic_lemma.md │ ├── math_linear_function.md │ ├── math_linear_modmin.md │ ├── math_modfactorial.md │ ├── math_modint.md │ ├── math_modpoly.md │ └── string_z_algo.md ├── data_structure │ ├── cartesian_tree.cpp │ ├── count_distinct.cpp │ ├── fenwick.cpp │ ├── fenwick2d.cpp │ ├── linkcut.cpp │ ├── range_sum.cpp │ └── splay.cpp ├── etc │ └── max_sumarray.cpp ├── geometry │ ├── circle.cpp │ ├── point.cpp │ └── polar_sort.cpp ├── graph │ ├── dinic.cpp │ ├── mcmf.cpp │ └── scc.cpp ├── math │ ├── euler_phi.cpp │ ├── fft.cpp │ ├── floor_sum.cpp │ ├── harmonic_lemma.cpp │ ├── linear_function.cpp │ ├── linear_modmin.cpp │ ├── modfactorial.cpp │ ├── modint.cpp │ └── modpoly.cpp └── string │ └── z_algo.cpp └── template.cpp /README.md: -------------------------------------------------------------------------------- 1 | 공사 중입니다. 2 | -------------------------------------------------------------------------------- /_TODO_cleanup/linear_function.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp_math/linear_function.cpp 2 | 3 | 일차함수 타입입니다. int, double, [modint](https://github.com/jh05013/BOJ_algorithms/wiki/modint-%28cpp%29) 등 사칙연산을 지원하는 타입에 대해 사용할 수 있습니다. 4 | 5 | ## Declaration 6 | - `Linear()`은 `0x + 0`을 반환합니다. 7 | - `Linear(b)`는 `0x + b`를 반환합니다. 8 | - `Linear(a, b)`는 `ax + b`를 반환합니다. 9 | 10 | ## Methods 11 | - 입력, 출력, 비교, 사칙연산을 지원합니다. 12 | - 입력은 stdin으로부터 `a`와 `b`를 차례로 입력받습니다. 13 | - 곱셈은 두 일차함수의 곱에서 `x^2` 항을 제거한 것, 즉 `f*g modulo x^2`를 반환합니다. 14 | - 나눗셈은 `h*g == f`인 일차함수 `h`를 반환합니다. **나눗셈이 정확하게 정의된 타입에 대해서만 사용하세요.** 그렇지 않으면 UB입니다. 예를 들어, `Linear`의 나눗셈을 하면 안 됩니다. 15 | - `composite(f, g)`는 `h(x) = f(g(x))`인 일차함수 `h`를 반환합니다. -------------------------------------------------------------------------------- /_TODO_cleanup/linkcut.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp_ds/linkcut.cpp 2 | 3 | 이 문서에서, 4 | - `x`, `y`는 노드 포인터입니다. 5 | - "`x`의 전역 트리"란, 모든 간선이 포함된 포레스트 중 노드 `x`를 포함하는 트리를 의미합니다. 6 | - "`x`의 스플레이 트리"란, 노드 `x`를 포함하는 스플레이 트리를 의미합니다. 하나의 전역 트리는 여러 개의 스플레이 트리로 이루어져 있습니다. 7 | 8 | # `LinkCut` 9 | ## Declaration 10 | - `LinkCut(arr)`은 노드(`Snode`)의 개수가 `arr`의 길이와 같고, 노드의 내용물이 순서대로 `arr`의 내용물과 같으며, 아무 간선도 없는 링크/컷 트리를 만듭니다. 노드의 번호는 순서대로 0, 1, 2, ...입니다. 11 | - 노드의 번호를 1, 2, 3, ...으로 하려면, `arr`의 맨 앞에 아무 거나 하나 집어넣으세요. 12 | 13 | ## Fields 14 | - `n`은 노드의 개수입니다. 15 | - `nodes`는 모든 노드를 담은 배열입니다. `nodes[i]`의 번호는 `i`입니다. 16 | 17 | ## Methods 18 | - `new_node(c)`는 내용물이 `c`인 새로운 노드를 만듭니다. 이 노드의 번호는 지금까지 부여되지 않은 음이 아닌 정수 중 가장 작은 값입니다. 19 | - `input(cnt)`은 stdin으로부터 두 정수 a와 b를 받아, a번과 b번 노드를 연결하는 작업을 `cnt`번 반복합니다. 20 | - `access(x)`는 `x`에서부터 `x`의 전역 트리의 루트까지 하나의 스플레이 트리로 묶습니다. 또한, `access`가 호출되기 전 그 루트의 스플레이 트리 안에 포함된 노드 중, `x`와 가장 가까운 것을 반환합니다. 21 | - `link(x, y)`는 `y`를 `x`의 부모로 둡니다. 22 | - x의 부모가 이미 있으면 RTE입니다. 23 | - y가 x의 자손이면 UB입니다. 24 | - `cut(x)`는 `x`와 `x`의 부모 사이 연결을 제거합니다. 25 | - x의 부모가 없으면 RTE입니다. 26 | - `path(x, y)`는 **루트를 `x`로 바꾸고**, `x`에서 `y`로 가는 경로를 나타내는 노드를 반환합니다. 27 | - `path_update(x, y, v)`는 `path(x, y)`에 lazy 값 `v`를 반영합니다. 28 | - `lca(x, y)`는 `x`와 `y`의 LCA에 해당하는 노드를 반환합니다. 29 | - x와 y가 다른 전역 트리에 있으면 UB입니다. 30 | - `root(x)`는 `x`의 전역 트리의 루트 노드를 반환합니다. 31 | - `is_root(x)`는 `x`가 자신의 전역 트리의 루트 노드이면 true, 아니면 false를 반환합니다. 32 | - `parent(x)`는 `x`의 전역 트리 상에서 자신의 부모 노드를 반환합니다. 33 | - 부모가 없으면 RTE입니다. 34 | - `depth(x)`는 `x`의 전역 트리 상에서 자신의 깊이를 반환합니다. 루트의 깊이는 0입니다. 35 | - `reroot(x)`는 루트를 `x`로 바꿉니다. 36 | - `connect(x, y)`는 **루트를 `x`로 바꾸고**, `x`와 `y`를 간선으로 연결합니다. 37 | - `disconnect(x, y)`는 **루트를 `x`로 바꾸고**, `x`와 `y` 사이 간선을 제거합니다. 38 | - 간선이 없으면 RTE입니다. 39 | - `connected(x, y)`는 `x`와 `y`가 같은 전역 트리 상에 있으면 true, 아니면 false를 반환합니다. 40 | - `access`부터 `connected`까지 모두, `x`와 `y`에 노드 대신 노드의 번호를 줄 수 있습니다. 이 경우 `lca`, `root`, `parent`는 노드의 번호를 반환하고, 나머지는 위에 명시한 것과 같습니다. 41 | 42 | # `Snode` 43 | ## Declaration 44 | - 사용자는 다음 정의를 수정해야 합니다. **뒤집는 연산은 링크/컷 트리에서 필수이기 때문에, `lazy`가 아닌 `doflip`으로 변수를 따로 만들어 놓았습니다. 따라서 `slazy_t`에 이 정보가 또 있으면 안 됩니다.** 45 | - `scont_t`: 노드의 내용물을 나타내는 타입. 46 | - `snode_t`: 서브트리의 값을 나타내는 타입. 47 | - `leaf_val(c)`: 노드의 자손이 없고, 내용물이 `c`일 때, 이를 서브트리 값으로 바꾸어 반환하는 함수. 48 | - `combine(a, b)`: 서브트리 값 `a`와 `b`를 합친 새 서브트리 값을 반환하는 함수. 49 | - `slazy_t`: 노드의 lazy 값을 나타내는 타입. 50 | - `LID`: lazy 업데이트가 없음을 의미하는 lazy 값. 노드의 lazy 값이 `LID`와 같을 경우 아래 `unlazy` 함수는 호출되지 않습니다. 51 | - `combine_lazy(a, b)`: 노드의 lazy 값이 `a`이고, 여기에 `b`를 반영했을 때, 새 lazy 값을 반환하는 함수. 52 | - `unlazy()`: 노드의 lazy 값으로부터 내용물 및 서브트리 값을 갱신하는 함수. 53 | - `undoflip()`: 노드의 내용물 및 서브트리 값을 뒤집는 함수. 54 | - 사용자는 `Snode`를 선언하면 안 됩니다. `Snode`는 `LinkCut` 내부에서만 사용됩니다. 55 | 56 | ## Fields 57 | - `content`는 노드의 내용물입니다. 58 | - `no`는 노드의 번호입니다. 59 | - `val`은 노드를 루트로 하는 서브트리의 값입니다. 60 | - `cnt`는 노드를 루트로 하는 서브트리의 크기입니다. 61 | 62 | ## Methods 63 | - `lazy_add(v)`는 노드에 lazy 값 `v`를 반영합니다. 64 | 65 | # TODO 66 | - `Snode`에서 사용자가 정의해야 되는 부분만 따로 빼서 별도로 정의하도록 바꾸기 67 | - `LinkCut`에 `connect_weighted`, `disconnect_weighted` 추가하기 68 | 69 | # 참고 자료 70 | - 튜토리얼: [Link Cut Tree](https://imeimi.tistory.com/27?category=256657) by imeimi 71 | - 구현: [Link Cut Tree implementation](https://codeforces.com/blog/entry/75885) by bicsi 72 | - 구현: [LinkCutTree.cpp](https://github.com/justiceHui/AlgorithmImplement/blob/master/DataStructure/LinkCutTree.cpp) by jhnah917 73 | 74 | # 테스트 문제 75 | - [BOJ 트리와 쿼리 11](https://www.acmicpc.net/problem/13539) link, cut, LCA 76 | - [BOJ 트리와 쿼리 12](https://www.acmicpc.net/problem/16912) connect, disconnect, connected 77 | - [LC Dynamic Tree Vertex Add Path Sum](https://judge.yosupo.jp/problem/dynamic_tree_vertex_add_path_sum) connect, disconnect, path query 78 | - [LC Dynamic Tree Vertex Set Path Composite](https://judge.yosupo.jp/problem/dynamic_tree_vertex_set_path_composite) connect, disconnect, path query 79 | - [DMOJ Dynamic Tree Test (Easy)](https://dmoj.ca/problem/ds5easy) reroot, connect, disconnect, path query, lca 80 | 81 | 아래는 LC Dynamic Tree Vertex Set Path Composite에서의 사용 예시입니다. `Linear`는 [linear function](https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/_doc/math_linear_function.md), `modint`는 [modint](https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/_doc/math_modint.md)를 참조하세요. 82 | ```cpp 83 | struct Snode{ 84 | typedef Linear scont_t; // element 85 | typedef pair, Linear> snode_t; 86 | snode_t leaf_val(scont_t c){ 87 | return {c, c}; 88 | } 89 | // a left, b right 90 | snode_t combine(snode_t a, snode_t b){ 91 | auto [a1, a2] = a; auto [b1, b2] = b; 92 | return {composite(b1, a1), composite(a2, b2)}; 93 | } 94 | 95 | typedef pair slazy_t; 96 | const slazy_t LID = {-1, -1}; 97 | // apply a <- b 98 | slazy_t combine_lazy(slazy_t a, slazy_t b){ 99 | return b; 100 | } 101 | void unlazy(){ 102 | content = Linear(lazy.first, lazy.second); 103 | } 104 | void undoflip(){ 105 | val = {val.second, val.first}; 106 | } 107 | //////////////////////////////////////////////////////////// 108 | //(skipped...) 109 | }; 110 | 111 | //(skipped...) 112 | 113 | int main(){OJize(); 114 | int n, Q; cin>>n>>Q; 115 | vector> arr(n); 116 | for(int i=0; i>arr[i]; 117 | LinkCut LCT(arr); 118 | for(int i=0; i>x>>y; 120 | LCT.connect(x, y); 121 | } 122 | 123 | while(Q--){ 124 | int qty; cin>>qty; 125 | if(qty == 0){ 126 | int a, b; 127 | cin>>a>>b, LCT.disconnect(a, b); 128 | cin>>a>>b, LCT.connect(a, b); 129 | } 130 | else if(qty == 1){ 131 | int v, a, b; cin>>v>>a>>b; 132 | LCT.path_update(v, v, {a, b}); 133 | } 134 | else{ 135 | int a, b, x; cin>>a>>b>>x; 136 | cout << LCT.path(a, b)->val.first(x) << '\n'; 137 | } 138 | } 139 | } 140 | ``` -------------------------------------------------------------------------------- /_TODO_cleanup/modint.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp_math/modint.cpp 2 | 3 | 특정 상수 `MOD`를 모듈로 값으로 갖는 정수 타입입니다. 4 | 5 | ## Declaration 6 | - `modint()`는 modint 0을 반환합니다. 7 | - `modint(v)`는 v를 `MOD`로 나눈 값의 modint를 반환합니다. 8 | 9 | ## Methods 10 | - 입력, 출력, 비교, 사칙연산을 지원합니다. 11 | - 나눗셈은 `MOD`가 소수일 때만 사용하세요. 그렇지 않으면 UB입니다. 12 | - `a / b`의 시간 복잡도는 O(MOD)입니다. 나머지 연산의 시간 복잡도는 O(1)입니다. 13 | - `inv(a)`는 `1 / a`를 반환합니다. 시간 복잡도는 O(MOD)입니다. 14 | - `ipow(a, p)`는 `a`의 `p`제곱을 반환합니다. 시간 복잡도는 O(log p)입니다. -------------------------------------------------------------------------------- /_TODO_cleanup/z_algo.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/string/z_algo.cpp 2 | 3 | Z 알고리즘을 정의합니다. 4 | 5 | # Z algorithm 6 | `vector z_algo(string &s)` or `vector z_algo(vector &s){` 7 | - 인자 8 | - `s`는 문자열 또는 vector입니다. 길이는 n입니다. 9 | - 동작 10 | - 길이가 n인 `vector z`를 반환합니다. 11 | - `z[i]`는 `s`와 `s[i..]`의 최장 공통 접두사의 길이와 같습니다. 12 | - 시간 복잡도: O(n) 13 | 14 | # 테스트 문제 15 | - [LC Z Algorithm](https://judge.yosupo.jp/problem/zalgorithm) 16 | 17 | 아래는 LC Z Algorithm에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/85457) 18 | 19 | ```cpp 20 | int main(){ 21 | string s; cin>>s; 22 | for(int x: z_algo(s)) cout< arr)`는 `arr`의 카르테시안 트리를 선언합니다. 부모 쪽으로 올라갈 수록 값이 작아집니다. 5 | - 시간 복잡도: `O(n)` 6 | 7 | # 필드 8 | - `P`는 각 정점의 부모 정점 번호를 담는 배열입니다. 루트면 자기 자신입니다. 9 | - `L`은 각 정점의 왼쪽 자식 정점 번호를 담는 배열입니다. 왼쪽 자식이 없으면 -1입니다. 10 | - `R`은 각 정점의 오른쪽 자식 정점번호를 담는 배열입니다. 오른쪽 자식이 없으면 -1입니다. 11 | 12 | # 테스트 문제 13 | - [LC Cartesian Tree](https://judge.yosupo.jp/problem/cartesian_tree) 14 | - 모든 "히스토그램에서 가장 큰 직사각형" 문제들 15 | 16 | 다음은 LC Cartesian Tree에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/99003) 17 | ```cpp 18 | int main(){OJize(); 19 | int n; cin>>n; 20 | vector arr(n); for(int i=0; i>arr[i]; 21 | CartesianTree CT(arr); 22 | for(int x: CT.P) cout << x << ' '; 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /cpp/_doc/ds_count_distinct.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/data_structure/count_distinct.cpp 2 | 3 | 범위 안에 있는 서로 다른 수의 개수를 효율적으로 구하는 자료구조입니다. [다음 링크](http://www.secmem.org/blog/2021/07/19/distinct-value-query/)를 참조했습니다. 4 | 5 | # 선언 6 | - const int `CDSZ`와 `CDCNT`는 기본값이 각각 400과 2500이고, 수정이 필요할 경우 직접 코드에서 수정하여야 합니다. 7 | - `CountDistinct(vector arr)`은 내용물이 `arr`인 CountDistinct 자료구조를 선언합니다. 8 | - `arr`의 크기 `n <= CDSZ * CDCNT`여야 합니다. 9 | - 선언의 시간 복잡도는 O(nlogn + CDCNT^2)입니다. 10 | 11 | # 연산 12 | - `query(int l, int r)`은 `arr[l], ..., arr[r]` 중 서로 다른 수의 개수를 반환합니다. 13 | - 시간 복잡도는 O(CDSZ)입니다. 14 | 15 | # 상수 조정 16 | TODO 17 | 18 | # 테스트 문제 19 | - [BOJ 14898 서로 다른 수와 쿼리 2](https://acmicpc.net/problem/14898) 20 | 21 | `CDSZ`와 `CDCNT`가 기본값일 때 메모리 135 MB, 시간 2.5초가 소요됩니다. 22 | 23 | ```cpp 24 | int main(){OJize(); 25 | int n; cin>>n; 26 | vector arr(n); 27 | for(int i=0; i>arr[i]; 28 | CountDistinct CD(arr); 29 | int pans = 0, Q; cin>>Q; 30 | while(Q--){ 31 | int l,r; cin>>l>>r; 32 | l+= pans; 33 | pans = CD.query(l-1, r-1); 34 | cout << pans << '\n'; 35 | } 36 | } 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /cpp/_doc/ds_fenwick.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/data_structure/fenwick.cpp 2 | 3 | 펜윅 트리입니다. 4 | 5 | # 선언 6 | - `Fenwick(int n)`은 `content`의 크기가 n인 펜윅 트리를 선언합니다. 7 | 8 | # 필드 9 | - `vector content` - 구간 합이 아닌 원래의 내용물을 담는 vector입니다. 10 | 11 | # 연산 12 | 아래에서 서술하는 모든 연산의 시간 복잡도는 `O(logn)`입니다. 13 | 14 | **업데이트** 15 | - `add(int i, T val)`은 `content[i]`에 `val`을 더합니다. 16 | - `change(int i, T val)`은 `content[i]`의 값을 `val`로 바꿉니다. 17 | 18 | **쿼리** 19 | - `sum(int i)`는 `content[0] + ... + content[i]`입니다. 20 | - `sum(int i, int j)`는 `content[i] + ... + content[j]`입니다. 21 | - `kth(int k)`는, **모든 content[i]가 0 이상**이라는 가정 하에, `content[0] + ... + content[i] >= k`인 최소의 i입니다. 그러한 i가 없으면 RTE입니다. 22 | 23 | # 테스트 문제 24 | - [BOJ 2042 구간 합 구하기](https://acmicpc.net/problem/2042) change, sum 25 | - [LC Point Add Range Sum](https://judge.yosupo.jp/problem/point_add_range_sum) add, sum 26 | - [BOJ 12899 데이터 구조](https://acmicpc.net/problem/12899) add, kth 27 | 28 | 다음은 LC Point Add Range Sum에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/88011) 29 | ```cpp 30 | int main(){OJize(); 31 | int n, Q; cin>>n>>Q; 32 | Fenwick F(n); 33 | for(int i=0; i>x; 35 | F.add(i, x); 36 | } 37 | while(Q--){ 38 | ll qty, a, b; cin>>qty>>a>>b; 39 | if(qty == 0) F.add(a, b); 40 | else cout << F.sum(a, b-1) << '\n'; 41 | } 42 | } 43 | ``` 44 | 45 | 다음은 BOJ 12899 데이터 구조에서의 사용 예시입니다. 채점 결과: 860 ms, 18412 KB 46 | ```cpp 47 | int main(){OJize(); 48 | int Q; cin>>Q; 49 | Fenwick F(2000001); 50 | while(Q--){ 51 | int qty, x; cin>>qty>>x; 52 | if(qty == 1){F.add(x, 1); continue;} 53 | int v = F.kth(x); F.add(v, -1); 54 | cout << v << '\n'; 55 | } 56 | } 57 | ``` -------------------------------------------------------------------------------- /cpp/_doc/ds_fenwick2d.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/data_structure/fenwick2d.cpp 2 | 3 | 이차원 펜윅 트리입니다. 4 | 5 | # 선언 6 | - `Fenwick2d(int n, int m)`은 `content`의 크기가 n*m인 펜윅 트리를 선언합니다. 7 | 8 | # 필드 9 | - `vector> content` - 구간 합이 아닌 원래의 내용물을 담는 vector입니다. 10 | 11 | # 연산 12 | 아래에서 서술하는 모든 연산의 시간 복잡도는 `O(logn)`입니다. 13 | 14 | **업데이트** 15 | - `add(int i, int j, T val)`은 `content[i][j]`에 `val`을 더합니다. 16 | - `change(int i, int j, T val)`은 `content[i][j]`의 값을 `val`로 바꿉니다. 17 | 18 | **쿼리** 19 | - `sum(int i, int j)`는 모든 `0 <= x <= i, 0 <= y <= j`에 대한 `content[x][y]`의 합입니다. 20 | - `sum(int i1, int j1, int i2, int j2)`는 모든 `i1 <= x <= i2, j1 <= y <= j2`에 대한 `content[x][y]`의 합입니다. 21 | 22 | # 테스트 문제 23 | - [BOJ 11658 구간 합 구하기 3](https://www.acmicpc.net/problem/11658) 24 | 25 | 18 MB, 200 ms 26 | 27 | ```cpp 28 | int main(){OJize(); 29 | int n, Q; cin>>n>>Q; 30 | Fenwick2D F(n, n); 31 | for(int i=0; i>x; 33 | F.add(i, j, x); 34 | } 35 | while(Q--){ 36 | int qty; cin>>qty; 37 | if(qty == 1){ 38 | int i1,j1,i2,j2; cin>>i1>>j1>>i2>>j2; 39 | cout << F.sum(i1-1, j1-1, i2-1, j2-1) << '\n'; 40 | continue; 41 | } 42 | int i, j; ll x; cin>>i>>j>>x; 43 | F.change(i-1, j-1, x); 44 | } 45 | } 46 | ``` -------------------------------------------------------------------------------- /cpp/_doc/ds_range_sum.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/data_structure/range_sum.cpp 2 | 3 | 배열 `A`의 구간 합을 구하는 자료구조입니다. 4 | 5 | # 선언 6 | - `RangeSum(int N)`은 크기 `N`의, 모든 `A[i] = 0`인 구간 합 자료구조를 선언합니다. 7 | - `RangeSum(vector A)`는 배열 A에 대한 구간 합 자료구조를 선언합니다. 이때 `enter` 연산은 사용할 수 없습니다. 8 | 9 | # 필드 10 | - `n`은 배열 A의 크기입니다. 11 | 12 | # 연산 13 | 모든 연산의 시간복잡도는 amortized `O(1)`입니다. 14 | - `enter(int i, T x)`는 `A[i] = x`로 둡니다. 15 | - `0 <= i < n`이어야 합니다. 안 그러면 RTE입니다. 16 | - `i` 값은 가장 최근에 호출한 `enter`의 `i` 값보다 커야 하며, 지금까지 호출되었던 모든 `sum`의 `r` 값보다 커야 합니다. 안 그러면 RTE입니다. 17 | - `sum(int l, int r)`은 `A[l] + ... + A[r]`입니다. 18 | - `0 <= l <= r < n`이어야 합니다. 안 그러면 RTE입니다. 19 | 20 | # 테스트 문제 21 | - [BOJ 11659 구간 합 구하기 3](https://acmicpc.net/problem/11659) 22 | - [LC Static Range Sum](https://judge.yosupo.jp/problem/static_range_sum) 23 | - [BOJ 16139 인간-컴퓨터 상호작용](https://www.acmicpc.net/problem/16139) 24 | 25 | 다음은 LC Static Range Sum에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/104681) 26 | ```cpp 27 | int main(){OJize(); 28 | int n, Q; cin>>n>>Q; 29 | vector arr(n); 30 | for(int i=0; i>arr[i]; 31 | RangeSum RS(arr); 32 | while(Q--){ 33 | int l, r; cin>>l>>r; 34 | cout << RS.sum(l, r-1) << '\n'; 35 | } 36 | } 37 | ``` 38 | 39 | 이렇게도 사용할 수 있습니다. [채점 결과](https://judge.yosupo.jp/submission/104682) 40 | ```cpp 41 | int main(){OJize(); 42 | int n, Q; cin>>n>>Q; 43 | RangeSum RS(n); 44 | for(int i=0; i>x; 46 | RS.enter(i, x); 47 | } 48 | while(Q--){ 49 | int l, r; cin>>l>>r; 50 | cout << RS.sum(l, r-1) << '\n'; 51 | } 52 | } 53 | ``` 54 | 55 | 다음은 BOJ 16139 인간-컴퓨터 상호작용에서의 사용 예시입니다. [채점 결과](https://www.acmicpc.net/source/share/8aea43f883c342b7bc5db32499037988) 56 | ```cpp 57 | int main(){OJize(); 58 | string s; cin>>s; 59 | vector> RS(26, RangeSum(sz(s))); 60 | for(int i=0; i>Q; 63 | while(Q--){ 64 | char c; int l, r; cin>>c>>l>>r; 65 | cout << RS[c-'a'].sum(l, r) << '\n'; 66 | } 67 | } 68 | ``` -------------------------------------------------------------------------------- /cpp/_doc/etc_max_sumarray.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/etc/max_sumarray.cpp 2 | 3 | `T max_sumarray(vector arr)`은 `arr`의 비어있지 않은 연속한 부분수열 중 최대 합을 반환합니다. 4 | - `arr`이 비어있으면 RTE입니다. 5 | - 시간 복잡도: `O(n)` 6 | 7 | # 테스트 문제 8 | - [BOJ 1912 연속합](https://www.acmicpc.net/problem/1912) 9 | 10 | 8 ms, 3588 kB 11 | 12 | ```cpp 13 | int main(){OJize(); 14 | int n; cin>>n; 15 | vector A(n); for(auto &x: A) cin>>x; 16 | cout << max_sumarray(A); 17 | } 18 | ``` 19 | -------------------------------------------------------------------------------- /cpp/_doc/geometry_point.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/geometry/point.cpp 2 | 3 | 2차원 점 `Pnt`를 정의합니다. 4 | 5 | # 각도 변환 6 | - `to_radian(deg)`는 `deg`도를 라디안으로 변환합니다. 7 | - `to_degree(rad)`는 `rad` 라디안을 도로 변환합니다. 8 | 9 | # 필드 10 | - `T x` - x 좌표 11 | - `T y` - y 좌표 12 | - `int idx` - 점의 레이블. int가 아닌 다른 레이블을 원하실 경우, 레이블을 모아 놓은 vector를 만들어서 사용하십시오. 13 | 14 | 연산 내부적으로는 좌표 범위의 제곱에 이르는 수를 사용합니다. `T`가 `long long`일 경우, 좌표의 절댓값은 10^9 이하여야 합니다. 15 | 16 | # 선언 17 | - `Pnt()` - (0, 0)을 선언합니다. 18 | - `Pnt(x, y)` - (x, y)를 선언합니다. 19 | - `Pnt(x, y, idx)` - 레이블이 `idx`인 점 (x, y)를 선언합니다. 20 | 21 | # 연산 22 | ## 입출력 23 | - `cin >>`으로 x, y좌표를 입력받을 수 있습니다. 24 | - `cout <<`으로 `(x, y)`를 출력할 수 있습니다. 25 | 26 | ## 기본 연산 27 | - 두 점의 덧셈과 뺄셈을 지원합니다. 28 | - 점과 스칼라의 곱셈과 나눗셈을 지원합니다. 29 | - 두 점의 비교를 지원합니다. 비교의 결과는 각 점의 x, y좌표 순서쌍을 비교한 결과와 같습니다. 30 | - `T dot(Pnt p, Pnt q)`는 두 점의 위치 벡터의 내적입니다. 31 | 32 | ## 거리 33 | - `T sq(Pnt p)`는 원점과 p 사이 거리의 제곱입니다. 34 | - `double abs(Pnt p)`는 원점과 p 사이 거리입니다. 35 | - `T distsq(Pnt p, Pnt q)`는 p와 q 사이 거리의 제곱입니다. 36 | - `double dist(Pnt p, Pnt q)`는 p와 q 사이 거리입니다. 37 | 38 | ## 각도 39 | - `int ccw(Pnt p, Pnt q, Pnt r)`은 p, q, r이 반시계 방향으로 놓여 있으면 -1, 한 직선 위에 놓여 있으면 0, 시계 방향으로 놓여 있으면 1입니다. 40 | - `T orient(Pnt p, Pnt q, Pnt r)`은 절댓값이 삼각형 pqr의 넓이의 두 배이고, 부호가 `ccw(p, q, r)`과 동일한 수입니다. 41 | - TODO angle, etc. 42 | 43 | ## 변형 44 | - `Pnt scale(Pnt c, Pnt p, T factor)`는 c를 기준으로 p의 위치를 factor배 한 점입니다. 45 | - `Pnt rot90(Pnt p)`는 원점을 기준으로 p를 반시계 방향으로 90도 회전시킨 점입니다. 46 | - `Pnt rot90(Pnt c, Pnt p)`는 c를 기준으로 p를 반시계 방향으로 90도 회전시킨 점입니다. 47 | - TODO theta rotation 48 | 49 | # 테스트 문제 50 | - [BOJ 11758 CCW](https://acmicpc.net/problem/11758) `ccw` 51 | - [eolymp 1614 Angles of triangle](https://www.eolymp.com/en/problems/1614) `angle` 52 | - [eolymp 2129 Polar angle of a point](https://www.eolymp.com/en/problems/2129) `angle_ccw` 53 | - [eolymp 5190 Сonstruct a triangle with two sides and the included angle](https://www.eolymp.com/en/problems/5190) `rot` -------------------------------------------------------------------------------- /cpp/_doc/geometry_polar_sort.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/geometry/polar_sort.cpp 2 | 3 | 점의 각도 정렬 관련 함수를 정의합니다. 4 | 5 | # Polar sort 6 | `void polar_sort(vector> &P, Pnt c)` 7 | - 인자 8 | - `P`는 정렬할 점의 vector입니다. 길이는 n입니다. c와 같은 점이 존재하면 RTE입니다. 9 | - `c`는 정렬의 기준이 되는 점입니다. 10 | - 동작 11 | - `P`의 점들을 `c`를 기준으로 반시계 방향으로 정렬합니다. 12 | - `P`에서 맨 처음에 오는 점은 `c`를 기준으로 -x축에서 반시계방향으로 재었을 때, 각도가 양수이면서 가장 작은 점입니다. 13 | - 각도가 같을 경우, `c`에서의 거리가 작을수록 먼저 옵니다. 14 | - 시간 복잡도: O(nlogn) 15 | 16 | # Halfplanes for polar-sorted points 17 | ⚠️ 한 문제 이상에서 잘 돌아감을 확인했으나, 충분한 테스트가 이루어지지는 않았습니다. 18 | 19 | `vector polar_sorted_halfplanes(vector> &P, const Pnt &c)` 20 | - 인자 21 | - `P`는 정렬할 점의 vector입니다. 길이는 n입니다. c와 같은 점이 존재하면 RTE입니다. 22 | - `c`는 정렬의 기준이 되는 점입니다. 23 | - `P`는 `c`를 기준으로 반시계 방향으로 정렬되어 있어야 합니다. 그렇지 않으면 UB입니다. 24 | - 동작 25 | - 길이가 n인 vector `R`을 반환합니다. 26 | - `R[i] < n`일 경우, `P[i], P[i+1], ..., P[R[i]]`는 모두 한 반평면 내에 있습니다. 이때 "반평면 내"는 경계도 포함합니다. 27 | - `R[i] >= n`일 경우, `P[i], P[i+1], ..., P[n-1], P[0], ..., P[R[i]-n]`는 모두 한 반평면 내에 있습니다. 28 | - TODO: R[i]가 "maximal"하다는 표현을 하고 싶은데, 좋은 표현 추천받습니다. 29 | - 시간 복잡도: O(n) 30 | 31 | # 테스트 문제 32 | - [LC Sort Points by Argument](https://judge.yosupo.jp/problem/sort_points_by_argument) 33 | 34 | 아래는 LC Sort Points by Argument에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/88002) 35 | ```cpp 36 | int main(){OJize(); 37 | int n; cin>>n; 38 | vector> P; 39 | int origins = 0; 40 | for(int i=0; i p; cin>>p; 42 | if(p != Pnt()) P.push_back(p); 43 | else origins++; 44 | } 45 | polar_sort(P, Pnt()); 46 | for(auto p: P){ 47 | if(p.y >= 0) while(--origins >= 0) cout<<"0 0\n"; 48 | cout<(int n, T INFTY)`는 정점 `n`개의 플로우 그래프 `G`를 선언합니다. 7 | - `T`는 간선의 용량의 타입입니다. 8 | - `INFTY`는 무한대 값입니다. 9 | 10 | # 그래프 만들기 11 | - `connect(s, e, cap)`은 `s`에서 `e`로 가는 용량 `cap`의 간선을 긋습니다. 12 | - 추가로, 그 간선을 찾는 데 사용되는 `EdgeIndex ei`를 반환합니다. `G[ei]`를 사용하면 됩니다. `G[ei].source, G[ei].target, G[ei].orig`는 각각 `s, e, cap`입니다. 13 | 14 | # 유량 구하기 15 | - `send(s, t)`는 `s`에서 `t`로 가는 최대 유량을 찾아 `{유량, 비용}` pair를 반환합니다. 16 | - `send`를 여러 번 호출하지 마세요. 17 | - 그 후, 특정 간선의 `EdgeIndex`가 `ei`일 때, `G[ei].used()`는 그 간선에서 사용된 유량을 반환합니다. 18 | 19 | # 테스트 문제 20 | - [BOJ 15892 사탕 줍는 로봇](https://www.acmicpc.net/problem/15892) 21 | - [LibreOJ 101 最大流](https://loj.ac/p/101) 22 | - [BOJ 11377 열혈강호 3](https://acmicpc.net/problem/11408) bipartite matching 23 | - [BOJ 11378 열혈강호 4](https://acmicpc.net/problem/11409) bipartite matching 24 | - [BOJ 17412 도시 왕복하기 1](https://www.acmicpc.net/problem/17412) 25 | 26 | 다음은 LibreOJ 101에서의 사용 예시입니다. [채점 결과](https://loj.ac/s/1597352) 27 | 28 | ```cpp 29 | int main(){OJize(); 30 | int n,m,s,t; cin>>n>>m>>s>>t; 31 | Dinic D(n+1, 0x3f3f3f3f4f3f3f3f); 32 | for (int i=0; i>a>>b>>c; 34 | D.connect(a, b, c); 35 | } 36 | cout << D.send(s, t); 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /cpp/_doc/graph_mcmf.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/graph/mcmf.cpp 2 | 3 | MCMF입니다. 4 | 5 | # 선언 6 | - `MCMF(int n, T INFTY)`는 정점 `n`개의 MCMF 그래프 `G`를 선언합니다. 7 | - `T`는 간선의 용량 및 비용의 타입입니다. 8 | - `INFTY`는 무한대 값입니다. 9 | 10 | # 그래프 만들기 11 | - `connect(s, e, cap, cost)`는 `s`에서 `e`로 가는 용량 `cap`, 비용 `cost`의 간선을 긋습니다. 12 | - `s != e`여야 합니다. 안 그러면 RTE입니다. 13 | - 추가로, 그 간선을 찾는 데 사용되는 `EdgeIndex ei`를 반환합니다. `G[ei]`를 사용하면 됩니다. `G[ei].source, G[ei].target, G[ei].cost, G[ei].orig`는 각각 `s, e, cost, cap`입니다. 14 | - **그래프에 음수 사이클이 있으면 UB입니다.** 15 | 16 | # 유량 구하기 17 | - `send(s, t)`는 `s`에서 `t`로 가는 최소 비용 최대 유량을 찾아 `{유량, 비용}` pair를 반환합니다. 18 | - `send`를 여러 번 호출하지 마세요. 19 | - 그 후, 특정 간선의 `EdgeIndex`가 `ei`일 때, `G[ei].used()`는 그 간선에서 사용된 유량을 반환합니다. 20 | 21 | # 테스트 문제 22 | - [BOJ 11408 열혈강호 5](https://acmicpc.net/problem/11408) bipartite matching 23 | - [BOJ 11409 열혈강호 6](https://acmicpc.net/problem/11409) bipartite matching 24 | - [LibreOJ 102 最小费用流](https://loj.ac/p/102) 25 | 26 | 다음은 LibreOJ 102에서의 사용 예시입니다. [채점 결과](https://loj.ac/s/1597372) 27 | 28 | ```cpp 29 | int main(){OJize(); 30 | int n, m; cin>>n>>m; 31 | MCMF G(n+1, 0x3f3f3f3f4f3f3f3f); 32 | for(int i=0; i>a>>b>>cap>>cost; 34 | G.connect(a, b, cap, cost); 35 | } 36 | auto [F, C] = G.send(1, n); 37 | cout << F << ' ' << C; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /cpp/_doc/graph_scc.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/graph/scc.cpp 2 | 3 | SCC입니다. 4 | 5 | # 선언 6 | - `SCC(int n)`는 정점 `n`개의 그래프 `G`를 선언합니다. 7 | - **0-indexed**입니다. 8 | 9 | # 그래프 만들기 10 | - `connect(a, b)`는 `a`에서 `b`로 가는 간선을 긋습니다. 11 | - `input(m, base)`는 `m`개의 간선을 표준 입출력으로 받습니다. `base`의 기본값은 0이고, 입력이 1-based로 들어올 경우 `base`를 1로 두면 됩니다. 12 | 13 | # SCC 구하기 14 | `input()`을 호출하지 않았다면, 먼저 `init()`을 호출해야 합니다. 15 | 16 | `init()`을 호출한 뒤에는, 17 | - `scx[v]`는 정점 `v`의 SCC 번호입니다. 18 | - 모든 간선 `a -> b`에 대해, `scx[a] <= scx[b]`가 성립합니다. 19 | - `sccs[i]`는 SCC 번호가 `i`인 모든 정점의 vector이고, 정점 번호는 오름차순으로 들어있습니다. 20 | - `dag`는 같은 SCC의 정점들을 하나로 묶었을 때 나타나는 그래프입니다. 21 | - `loopcnt[i]`는 같은 SCC의 정점들을 하나로 묶었을 때 SCC `i`에 있는 루프의 개수입니다. 22 | 23 | # 테스트 문제 24 | - [BOJ 2150 Strongly Connected Component](https://www.acmicpc.net/problem/2150) 25 | - [LC Strongly Connected Components](https://judge.yosupo.jp/problem/scc) 26 | - [BOJ 26157 즉흥 여행 (Hard)](https://www.acmicpc.net/problem/26157) 27 | 28 | 다음은 LC Strongly Connected Components에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/126633) 29 | 30 | ```cpp 31 | int main(){OJize(); 32 | int n, m; cin>>n>>m; 33 | SCC G(n); G.input(m); 34 | cout << G.sccnt << '\n'; 35 | for(auto &V: G.sccs){ 36 | cout << V.size() << ' '; 37 | for(int x: V) cout << x << ' '; 38 | cout << '\n'; 39 | } 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /cpp/_doc/math_euler_phi.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/euler_phi.cpp 2 | 3 | # Euler Phi 4 | `T euler_phi(T n)` 5 | - 인자 6 | - `n`은 양의 정수입니다. 7 | - 동작 8 | - `ϕ(n)`, 즉 `n`보다 작으면서 `n`과 서로소인 양의 정수의 개수를 반환합니다. 9 | - 시간 복잡도: O(√n) 10 | 11 | # 테스트 문제 12 | - [BOJ 11689 GCD(n, k) = 1](https://www.acmicpc.net/problem/11689) 13 | - [BOJ 4355 서로소](https://www.acmicpc.net/problem/4355) 14 | 15 | 다음은 BOJ 11689에서의 사용 예시입니다. 16 | 17 | ```cpp 18 | int main(){OJize(); 19 | while(1){ 20 | int n; cin>>n; 21 | if(n == 0) break; 22 | else cout << euler_phi(n) << '\n'; 23 | } 24 | } 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /cpp/_doc/math_fft.md: -------------------------------------------------------------------------------- 1 | FFT입니다. 2 | 3 | cf. [modpoly](https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/_doc/math_modpoly.md) 4 | 5 | # Simple 6 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/fft.cpp 7 | 8 | `vector polymul(vector X, vector Y)` 9 | - 인자 10 | - `X`와 `Y`는 정수 배열입니다. 11 | - 동작 12 | - `X`와 `Y`의 convolution을 반환합니다. 13 | - 시간 복잡도: O(nlogn) 14 | 15 | # Dual 16 | TODO 17 | 18 | # 수의 범위 19 | ⚠️ 충분한 실험을 거치지 않았습니다. 20 | 21 | 수의 범위가 특정 한도 이내여야 안전합니다. 다음은 각 코드의 사용 권장 범위입니다. 이때 `x`는 인자로 주어지는 배열의 원소들 중 최대 절댓값입니다. 22 | - **Simple, int + double**: `nx^2 <= 10^9` 23 | - **Simple, long long + long double**: `nx^2 <= 10^13` 24 | 25 | 다음 코드로 실험했습니다. 26 | 27 | ``` 28 | int main(){OJize(); 29 | int n, mx; cin>>n>>mx; 30 | vector X(n), Y(n); 31 | for(int i=0; i(X, Y); 34 | cout< X, Y; 52 | string s; cin>>s; 53 | for(char c: s) X.push_back(c - '0'); 54 | cin>>s; 55 | for(int i=0; i<2; i++) for(char c: s) Y.push_back(c - '0'); 56 | reverse(entire(X)); 57 | 58 | X = polymul(X, Y); 59 | cout << *max_element(entire(X)); 60 | } 61 | ``` 62 | -------------------------------------------------------------------------------- /cpp/_doc/math_floor_sum.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/floor_sum.cpp 2 | 3 | # Floor Sum 4 | `T floor_sum(T n, T m, T a, T b)` 5 | - 인자 6 | - `n`은 0 이상의 정수, `m`은 양의 정수, `a`, `b`는 0 이상의 정수입니다. 7 | - ⚠️ `a`, `b`가 음수일 때의 동작은 테스트해보지 않았습니다. 8 | - 동작 9 | - `i = 0, ..., n-1`에 대해 `floor((ai+b)/m)`의 합을 반환합니다. 10 | - 시간 복잡도: O(logm) 11 | 12 | # 테스트 문제 13 | - [LC Sum of Floor of Linear](https://judge.yosupo.jp/problem/sum_of_floor_of_linear) 14 | - [AtCoder practice2-C Floor Sum](https://atcoder.jp/contests/practice2/tasks/practice2_c) 15 | - [BOJ 8483 Earthquake](https://www.acmicpc.net/problem/8483) 16 | - [BOJ 16998 It's a Mod, Mod, Mod, Mod World](https://www.acmicpc.net/problem/16998) 17 | - [BOJ 8870 Zadanie próbne](https://www.acmicpc.net/problem/8870) 18 | 19 | 다음은 LC Sum of Floor of Linear에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/107083) 20 | 21 | ```cpp 22 | int main(){OJize(); 23 | int T; cin>>T; 24 | while(T--){ 25 | ll n,m,a,b; cin>>n>>m>>a>>b; 26 | cout << floor_sum(n,m,a,b) << '\n'; 27 | } 28 | } 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /cpp/_doc/math_harmonic_lemma.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/harmonic_lemma.cpp 2 | 3 | 양의 정수 n에 대해 floor(n/i)로 가능한 값은 O(sqrt(n))개 존재함이 알려져 있습니다. 이 값들을 얻어내는 함수를 정의합니다. 4 | 5 | # One number version 6 | `vector> harmonic_floor(T n)` 7 | - 인자 8 | - `n`은 양의 정수입니다. 정수가 아니면 UB입니다. 양수가 아니면 RTE입니다. 9 | - 동작 10 | - 튜플 `(x, l, r)`로 이루어진 vector를 반환합니다. 11 | - 각 `(x, l, r)`은 `floor(n/i) = x`인 `i`의 범위가 구간 `[l, r]`이라는 의미입니다. `x`에 대한 내림차순으로 정렬되어 있으며, `[l, r]`이 비어있지 않으면서 `x >= 1`인 튜플만 vector에 들어있습니다. 12 | - 시간 복잡도: O(sqrt(n)) 13 | 14 | `vector> harmonic_ceil(T n)`은 위와 같으나, `ceil(n/i)`를 사용하며, `x >= 2`인 튜플만 vector에 들어있습니다. 15 | 16 | # Two numbers version 17 | `vector> harmonic2_floor(T n, T m)` 18 | - 인자 19 | - `n`과 `m`은 양의 정수입니다. 정수가 아니면 UB입니다. 양수가 아니면 RTE입니다. 20 | - 동작 21 | - 튜플 `(x, y, l, r)`로 이루어진 vector를 반환합니다. 22 | - 각 `(x, y, l, r)`은 `floor(n/i) = x, floor(m/i) = y`인 `i`의 범위가 구간 `[l, r]`이라는 의미입니다. 23 | - 시간 복잡도: O(sqrt(n)) 24 | 25 | TODO implement `harmonic2_ceil` 26 | 27 | # 테스트 문제 28 | - [BOJ 15897 잘못 구현한 에라토스테네스의 체](https://www.acmicpc.net/problem/15897) one ceil 29 | 30 | 아래는 BOJ 15897 잘못 구현한 에라토스테네스의 체에서의 사용 예시입니다. 채점 결과: 4 ms, 4452 KB 31 | 32 | ```cpp 33 | int main(){ 34 | ll n; cin>>n; 35 | ll ans = 0; 36 | for(auto [x, l, r]: harmonic_ceil(n)) ans+= x*(r-l+1); 37 | cout << ans+1; 38 | } 39 | ``` 40 | -------------------------------------------------------------------------------- /cpp/_doc/math_linear_function.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/linear_function.cpp 2 | 3 | 일차함수 타입입니다. int, double, [modint](https://github.com/jh05013/BOJ_algorithms/wiki/modint-%28cpp%29) 등 사칙연산을 지원하는 타입에 대해 사용할 수 있습니다. 4 | 5 | # 필드 6 | - `T a` 7 | - `T b` 8 | 9 | # 선언 10 | - `Linear()`은 `0x + 0`입니다. 11 | - `Linear(T b)`는 `0x + b`입니다. 12 | - `Linear(T a, T b)`는 `ax + b`입니다. 13 | 14 | # 연산 15 | ## 입출력 16 | - `cin >>`으로 a, b를 입력받을 수 있습니다. 17 | - `cout <<`으로 일차식을 출력할 수 있습니다. 계수가 0인 항은 출력되지 않으며, `x`의 계수가 1이면 계수가 출력되지 않습니다. 18 | 19 | ## 기본 연산 20 | - 두 일차함수의 사칙연산 및 비교(같음과 다름)를 지원합니다. 21 | - 곱셈은 `x^2` 항을 제거한 것, 즉 `f*g modulo x^2`를 반환합니다. 22 | - 나눗셈은 `h*g modulo x^2 == f`인 일차함수 `h`를 반환합니다. **나눗셈이 정확하게 정의된 타입에 대해서만 사용하세요.** 그렇지 않으면 UB입니다. 예를 들어, `Linear`의 나눗셈을 하면 안 됩니다. 23 | - `composite(f, g)`는 `h(x) = f(g(x))`인 일차함수 `h`를 반환합니다. -------------------------------------------------------------------------------- /cpp/_doc/math_linear_modmin.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/linear_modmin.cpp 2 | 3 | credit: [EtvycAuRLZpb6hhe86x0 에디토리얼](https://github.com/ghudegy/2021/blob/main/factorial-editorial.pdf) 4 | 5 | # Linear Modulo Minimum 6 | `T linear_modmin(T a, T b, T N, T e)` 7 | - 인자 8 | - `a`, `b`, `N`, `e`는 음이 아닌 정수이며 `N > 0`입니다. 9 | - 동작 10 | - `x` = 0, ..., `e`에 대해 `(a*x+b)%N`의 최솟값을 반환합니다. 11 | - 시간 복잡도: O(log N) 12 | 13 | # 테스트 문제 14 | - [LC Min of Mod of Linear](https://judge.yosupo.jp/problem/min_of_mod_of_linear) 15 | 16 | [채점 결과](https://judge.yosupo.jp/submission/107409) 17 | 18 | ```cpp 19 | int main(){OJize(); 20 | int T; cin>>T; 21 | while(T--){ 22 | ll n,m,a,b; cin>>n>>m>>a>>b; 23 | cout << linear_modmin(a, b, m, n-1) << '\n'; 24 | } 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /cpp/_doc/math_modfactorial.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/modfactorial.cpp 2 | 3 | 상수 `MOD`를 모듈로 값으로 하여 팩토리얼을 계산합니다. 사용하려면 [modint](https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/modint.cpp)가 필요합니다. 4 | 5 | # 선언 6 | - `Modfact(N) mf`는 0부터 N까지에 대해 팩토리얼을 계산하는 자료구조를 선언합니다. 7 | - 선언의 시간 복잡도: O(N + log MOD) 8 | 9 | # 연산 10 | - `mf[i]`는 `i!` mod `MOD`입니다. 11 | - `0 <= i < N`이어야 합니다. 안 그러면 UB입니다. 12 | - 시간 복잡도: O(1) 13 | - `mf.binom(n, k)`는 `nCk`, 즉 `binom(n, k)` mod `MOD`를 반환합니다. 14 | - **MOD는 소수**여야 합니다. 안 그러면 UB입니다. 15 | - `0 <= n < N`, `0 <= k`여야 합니다. 안 그러면 UB입니다. 16 | - `n > k`이면 0을 반환합니다. 17 | - 시간 복잡도: O(1) 18 | 19 | # 테스트 문제 20 | [BOJ 13977 이항 계수와 쿼리](https://www.acmicpc.net/problem/13977) 21 | 22 | ```cpp 23 | int main(){OJize(); 24 | Modfact MF(4000001); 25 | int Q; cin>>Q; 26 | while(Q--){ 27 | int n,k; cin>>n>>k; 28 | cout << MF.binom(n, k) << '\n'; 29 | } 30 | } 31 | ``` -------------------------------------------------------------------------------- /cpp/_doc/math_modint.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/modint.cpp 2 | 3 | 특정 상수 `MOD`를 모듈로 값으로 갖는 정수 타입입니다. `MOD`는 기본값이 1,000,000,007입니다. 필요에 따라 다른 값으로 바꿔 사용하십시오. 4 | 5 | # 필드 6 | - `T val` 7 | 8 | # 선언 9 | - `modint()`은 0입니다. 10 | - `modint(ll v)`는 v를 `MOD`로 나눈 나머지입니다. 11 | 12 | # 연산 13 | ## 입출력 14 | - `cin >>`으로 val을 입력받을 수 있습니다. 15 | - `cout <<`으로 val을 출력할 수 있습니다. 16 | 17 | ## 기본 연산 18 | - `MOD` 상수가 같은 두 modint의 사칙연산 및 비교를 지원합니다. 19 | - **나눗셈은 `MOD`가 소수일 때만 사용하세요.** 그렇지 않으면 UB입니다. 20 | - `a / b`의 시간 복잡도는 O(log`MOD`)입니다. 21 | - `inv(a)`는 `1 / a`를 반환합니다. 시간 복잡도는 O(log`MOD`)입니다. 22 | - `ipow(a, p)`는 `a`의 `p`제곱을 반환합니다. 시간 복잡도는 O(log p)입니다. -------------------------------------------------------------------------------- /cpp/_doc/math_modpoly.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/math/modpoly.cpp 2 | 3 | 특정 상수 `MOD`를 모듈로 값으로 갖는 다항식 타입입니다. `MOD`는 기본값이 998,244,353이고, `PRIMITIVE_ROOT`는 기본값이 3입니다. 필요에 따라 바꿔서 사용하되, number-theoretic transform이 가능하도록 설정하십시오. 4 | 5 | # 필드 6 | - `vector P`는 순서대로 상수항, x의 계수, x^2의 계수, ...을 담고 있습니다. 7 | 8 | # 선언 9 | - `modint(int n)` 10 | - `modint(vector A)` 11 | 12 | # 연산 13 | ## 입출력 14 | - `cin >>`으로 `P[0]`부터 `P[n-1]`까지 입력받을 수 있습니다. 15 | - `cout <<`으로 `P[0]`부터 `P[n-1]`까지 출력할 수 있습니다. 16 | 17 | ## 연산 18 | - 덧셈 `O(n)` 19 | - 뺄셈 `O(n)` 20 | - 곱셈 `O(nlogn)` 21 | - 나눗셈 `O(nlogn)` 22 | - 나머지 `O(nlogn)` 23 | - `inv`: 1/P `O(nlogn)` 24 | - `derivative`: P' `O(n)` 25 | - `integral`: ∫P `O(nlogMOD)` 26 | - `log`: logP `O(n(logMOD + logn))` 27 | - `exp`: e^P `O(n(logMOD + logn))` 28 | - `multieval`: multipoint evaluation `O(nlog^2n)` 29 | 30 | # 테스트 문제 31 | - [LC Convolution](https://judge.yosupo.jp/problem/convolution_mod) ([채점 결과](https://judge.yosupo.jp/submission/104699)) 32 | - [LC Inv of Formal Power Series](https://judge.yosupo.jp/problem/inv_of_formal_power_series) ([채점 결과](https://judge.yosupo.jp/submission/105294)) 33 | - [LC Division of Polynomials](https://judge.yosupo.jp/problem/division_of_polynomials) ([채점 결과](https://judge.yosupo.jp/submission/105295)) 34 | - [LC Log of Formal Power Series](https://judge.yosupo.jp/problem/log_of_formal_power_series) ([채점 결과](https://judge.yosupo.jp/submission/105546)) 35 | - [LC Exp of Formal Power Series](https://judge.yosupo.jp/problem/exp_of_formal_power_series) ([채점 결과](https://judge.yosupo.jp/submission/105552)) 36 | - [LC Multipoint Evaluation](https://judge.yosupo.jp/problem/multipoint_evaluation) ([채점 결과](https://judge.yosupo.jp/submission/105448)) 37 | - [BOJ 18168 Game With Polynomials 2](https://www.acmicpc.net/problem/18168) 38 | -------------------------------------------------------------------------------- /cpp/_doc/string_z_algo.md: -------------------------------------------------------------------------------- 1 | https://github.com/jh05013/BOJ_algorithms/blob/master/cpp/string/z_algo.cpp 2 | 3 | `vector z_algo(string &s)` 또는 `vector z_algo(vector &s)`는 길이가 n인 `vector z`를 반환합니다. 4 | - `z[i]`는 `s`와 `s[i..]`의 최장 공통 접두사의 길이와 같습니다. 5 | - 시간 복잡도: O(n) 6 | 7 | # 테스트 문제 8 | - [LC Z Algorithm](https://judge.yosupo.jp/problem/zalgorithm) 9 | - [BOJ 13713 문자열과 쿼리](https://www.acmicpc.net/problem/13713) 10 | 11 | 아래는 LC Z Algorithm에서의 사용 예시입니다. [채점 결과](https://judge.yosupo.jp/submission/85457) 12 | 13 | ```cpp 14 | int main(){ 15 | string s; cin>>s; 16 | for(int x: z_algo(s)) cout< 2 | struct CartesianTree{ 3 | int n, root = -1; 4 | vector P, L, R; 5 | CartesianTree(vector arr): n{sz(arr)}, 6 | P(sz(arr), -1), L(sz(arr), -1), R(sz(arr), -1) { 7 | vector ls(n, -1), rs(n, -1); 8 | stack> S; 9 | for(int i=0; i x) S.pop(); 12 | if(!S.empty()) ls[i] = S.top().second; 13 | S.push({x, i}); 14 | } 15 | while(!S.empty()) S.pop(); 16 | for(int i=n-1; i>=0; i--){ 17 | T x = arr[i]; 18 | while(!S.empty() && S.top().first >= x) S.pop(); 19 | if(!S.empty()) rs[i] = S.top().second; 20 | S.push({x, i}); 21 | } 22 | for(int i=0; i xr) P[i] = ls[i], R[ls[i]] = i; 27 | else P[i] = rs[i], L[rs[i]] = i; 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /cpp/data_structure/count_distinct.cpp: -------------------------------------------------------------------------------- 1 | const int CDSZ = 400; 2 | const int CDCNT = 2500; 3 | template 4 | struct CountDistinct{ 5 | int n; 6 | vector prv, nxt; 7 | int bsum[CDCNT][CDCNT]; 8 | 9 | CountDistinct(vector V): n{sz(V)}, prv(n,-1), nxt(n,n) { 10 | assert(n <= CDSZ * CDCNT); 11 | memset(bsum, 0, sizeof bsum); 12 | map prvlast, nxtlast; 13 | for(int i=0; i=0; i--){ 19 | if(nxtlast.find(V[i]) != nxtlast.end()) nxt[i] = nxtlast[V[i]]; 20 | nxtlast[V[i]] = i; 21 | } 22 | for(int i=0; i br){ 33 | for(int i=l; i<=r; i++) ans+= (prv[i] >= l); 34 | return r-l+1 - ans; 35 | } 36 | ans = bsum[br][br]; 37 | if(bl) ans-= bsum[bl-1][br] + bsum[br][bl-1] - bsum[bl-1][bl-1]; 38 | bl*= CDSZ, br = (br+1)*CDSZ-1; 39 | for(; bl>l; bl--) ans+= (nxt[bl-1] <= br); 40 | for(; br= l); 41 | return r-l+1 - ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /cpp/data_structure/fenwick.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct Fenwick{ 3 | int lsz = 0; 4 | vector arr, content; 5 | Fenwick(int n){ 6 | int sz = 1; 7 | while(sz < n) lsz++, sz<<= 1; 8 | arr.resize(sz), content.resize(sz); 9 | } 10 | 11 | void add(int i, T val){ 12 | content[i]+= val; 13 | while(i < sz(arr)) arr[i]+= val, i|= i+1; 14 | } 15 | void change(int i, T val){add(i, val-content[i]);} 16 | T sum(int i){ 17 | T res = 0; 18 | while(i >= 0) res+= arr[i], i = (i&(i+1))-1; 19 | return res; 20 | } 21 | T sum(int i, int j){return sum(j)-(i? sum(i-1):0);} 22 | // kth is 1-indexed 23 | int kth(T k){ 24 | assert(arr.back() >= k); 25 | int l = 0, r = sz(arr); 26 | for(int i=0; i<=lsz; i++){ 27 | int mid = (l+r)>>1; 28 | ll val = mid? arr[mid-1]:arr.back(); 29 | if(val >= k) r = mid; 30 | else l = mid, k-= val; 31 | } 32 | return l; 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /cpp/data_structure/fenwick2d.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct Fenwick2D{ 3 | int n = 1, m = 1, real_n, real_m; 4 | vector> arr, content; 5 | Fenwick2D(int N, int M): real_n(N), real_m(M){ 6 | while(n < N) n<<= 1; 7 | while(m < M) m<<= 1; 8 | arr.resize(n, vector(m)); 9 | content.resize(real_n, vector(real_m)); 10 | } 11 | 12 | void add(int i, int j, T val){ 13 | assert(0 <= i && i < real_n && 0 <= j && j < real_m); 14 | content[i][j]+= val; 15 | for(int x=i; x=0; x = (x&(x+1))-1) 26 | for(int y=j; y>=0; y = (y&(y+1))-1) res+= arr[x][y]; 27 | return res; 28 | } 29 | T sum(int i1, int j1, int i2, int j2){ 30 | assert(0 <= i1 && i1 <= i2 && i2 < real_n); 31 | assert(0 <= j1 && j1 <= j2 && j2 < real_m); 32 | T ans = sum(i2, j2); 33 | if(i1) ans-= sum(i1-1, j2); 34 | if(j1) ans-= sum(i2, j1-1); 35 | if(i1 && j1) ans+= sum(i1-1, j1-1); 36 | return ans; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /cpp/data_structure/linkcut.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct LinkCut{ 3 | int n; 4 | vector nodes; 5 | 6 | LinkCut(vector conts): n(sz(conts)){ 7 | for(int i=0; ino = i; 10 | } 11 | } 12 | Node *new_node(typename Node::scont_t c){ 13 | nodes.push_back(new Node(c)); 14 | nodes.back()->no = n++; 15 | return nodes.back(); 16 | } 17 | void input(int cnt){ 18 | int a, b; 19 | while(cnt--) cin>>a>>b, connect(a, b); 20 | } 21 | 22 | // DO NOT USE THESE IN CLIENT CODES!!! 23 | void setpar(Node *par, Node *son, bool left){ 24 | if(son) son->p = par; 25 | if(left) par->l = son; 26 | else par->r = son; 27 | } 28 | void rotate(Node *x){ 29 | Node *p = x->p, *q = p->p; 30 | if(!p->is_root()) q->prop(); 31 | p->prop(), x->prop(); 32 | bool xdir = (x == p->l); 33 | if(!p->is_root()) setpar(q, x, (p == q->l)); 34 | else x->p = q; 35 | setpar(p, x->ch(!xdir), xdir), setpar(x, p, !xdir); 36 | p->refresh(), x->refresh(); 37 | } 38 | 39 | // splay methods. k, l, r are 1-indexed 40 | Node* splay(Node *x){ 41 | x->prop(); 42 | while(!x->is_root()){ 43 | Node *p = x->p, *q = p->is_root() ? nullptr : p->p; 44 | if(q) rotate((x == p->l) == (p == q->l) ? p : x); 45 | rotate(x); 46 | } 47 | return x; 48 | } 49 | 50 | // link-cut ops 51 | // make a chain from x to the root of its global tree 52 | // x becomes the root of its splay tree 53 | // return, among the vertices in the previous chain that 54 | // contains the global root, the closest one to x 55 | Node* access(Node *x){ 56 | splay(x); 57 | x->r = nullptr; x->refresh(); 58 | Node *ret = x; 59 | while(x->p){ 60 | Node *y = x->p; ret = y; 61 | splay(y); 62 | y->r = x; y->refresh(); 63 | splay(x); 64 | } 65 | return ret; 66 | } 67 | Node* access(int i){return access(nodes[i]);} 68 | 69 | // y becomes parent of x in the global forest 70 | // TODO abort if x and y are in the same comp 71 | void link(Node *x, Node *y){ 72 | access(x); access(y); assert(!x->l); 73 | x->l = y; y->p = x; 74 | x->refresh(); 75 | } 76 | void link(int x, int y){link(nodes[x], nodes[y]);} 77 | 78 | // cut x from its parent in the global forest 79 | void cut(Node *x){ 80 | access(x); assert(x->l); 81 | x->l = x->l->p = nullptr; 82 | x->refresh(); 83 | } 84 | void cut(int x){cut(nodes[x]);} 85 | 86 | // node representing a path x--y 87 | Node* path(Node *x, Node *y){reroot(x); access(y); return y;} 88 | Node* path(int x, int y){return path(nodes[x], nodes[y]);} 89 | void path_update(Node *x, Node *y, typename Node::slazy_t v){ 90 | path(x, y)->lazy_add(v); 91 | } 92 | void path_update(int x, int y, typename Node::slazy_t v){ 93 | path_update(nodes[x], nodes[y], v); 94 | } 95 | 96 | // find lca(x,y) in the global tree containing x and y 97 | Node* lca(Node *x, Node *y){access(x); return access(y);} 98 | int lca(int x, int y){return lca(nodes[x], nodes[y])->no;} 99 | 100 | // find root of the global tree containing x 101 | // that root is then splayed 102 | Node* root(Node *x){ 103 | access(x); 104 | while(x->l) x = x->l->prop(); 105 | return splay(x); 106 | } 107 | int root(int x){return root(nodes[x])->no;} 108 | bool is_root(Node *x){access(x); return !x->l;} 109 | bool is_root(int x){return is_root(nodes[x]);} 110 | 111 | // find parent of x in the global tree, and splay it 112 | Node* parent(Node *x){ 113 | access(x); x = x->prop()->l; assert(x); 114 | x->prop(); 115 | while(x->r) x = x->r->prop(); 116 | return splay(x); 117 | } 118 | int parent(int x){return parent(nodes[x])->no;} 119 | 120 | // find depth of x in the global tree containing x 121 | // root has depth 0 122 | int depth(Node *x){access(x); return x->l ? x->l->cnt : 0;} 123 | int depth(int x){return depth(nodes[x]);} 124 | 125 | // reroot x in its global tree 126 | Node* reroot(Node *x){access(x); return splay(x)->flip();} 127 | Node* reroot(int x){return reroot(nodes[x]);} 128 | 129 | // connect x and y in the global forest 130 | void connect(Node *x, Node *y){reroot(x); link(x, y);} 131 | void connect(int x, int y){connect(nodes[x], nodes[y]);} 132 | 133 | // disconnect x and y in the global forest 134 | void disconnect(Node *x, Node *y){reroot(x); 135 | assert(root(x) == x); 136 | assert(parent(y) == x); cut(y); 137 | } 138 | void disconnect(int x, int y){disconnect(nodes[x], nodes[y]);} 139 | 140 | // check whether x and y are in the same global tree 141 | bool connected(Node *x, Node *y){return root(x) == root(y);} 142 | bool connected(int x, int y){return connected(nodes[x], nodes[y]);} 143 | }; 144 | 145 | struct Snode{ 146 | typedef ll scont_t; // element 147 | typedef ll snode_t; 148 | snode_t leaf_val(scont_t c){ 149 | return c; 150 | } 151 | // a left, b right 152 | snode_t combine(snode_t a, snode_t b){ 153 | return a+b; 154 | } 155 | 156 | typedef ll slazy_t; 157 | const slazy_t LID = -666; // MUST BE AN UNUSED VALUE 158 | // apply a <- b 159 | slazy_t combine_lazy(slazy_t a, slazy_t b){ 160 | return a+b; 161 | } 162 | void unlazy(){ 163 | content+= lazy; 164 | val+= cnt * lazy; 165 | } 166 | void undoflip(){ 167 | ; 168 | } 169 | //////////////////////////////////////////////////////////// 170 | Snode *l = nullptr, *r = nullptr, *p = nullptr; 171 | scont_t content; int no = 0; 172 | snode_t val; 173 | slazy_t lazy = LID; bool doflip = false; 174 | int cnt = 1; 175 | 176 | Snode(scont_t c): content(c) {val = leaf_val(content);} 177 | 178 | // push, pull, and query 179 | Snode* refresh(){ 180 | val = leaf_val(content), cnt = 1; 181 | if(l) l->prop(), val = combine(l->val, val), cnt += l->cnt; 182 | if(r) r->prop(), val = combine(val, r->val), cnt += r->cnt; 183 | return this; 184 | } 185 | void lazy_add(slazy_t x){ 186 | lazy = combine_lazy(lazy, x); 187 | } 188 | Snode* flip(){doflip = !doflip; return this;} 189 | Snode* prop(){ 190 | if(doflip){ 191 | if(l) l->flip(); 192 | if(r) r->flip(); 193 | swap(l, r), undoflip(), doflip = false; 194 | } 195 | if(lazy != LID){ 196 | if(l) l->lazy_add(lazy); 197 | if(r) r->lazy_add(lazy); 198 | unlazy(), lazy = LID; 199 | } 200 | return this; 201 | } 202 | 203 | // helper funcs 204 | bool is_root(){return !p || (this != p->l && this != p->r);} 205 | bool is_left(){ 206 | assert(!p || p->lazy == LID); 207 | return p && p->l == this; 208 | } 209 | Snode *ch(bool left){ 210 | assert(lazy == LID); 211 | return left? l : r; 212 | } 213 | }; -------------------------------------------------------------------------------- /cpp/data_structure/range_sum.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct RangeSum{ 3 | int n; 4 | vector arr; 5 | 6 | RangeSum(vector A): n(sz(A)), arr(A) { 7 | for(int i=1; i r) return 0; 16 | return sum(max(0, l), min(n-1, r)); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /cpp/data_structure/splay.cpp: -------------------------------------------------------------------------------- 1 | struct Snode{ 2 | typedef int scont_t; // element 3 | typedef int snode_t; 4 | snode_t leaf_val(scont_t c){ 5 | return c; 6 | } 7 | // a left, b right 8 | snode_t combine(snode_t a, snode_t b){ 9 | return a+b; 10 | } 11 | 12 | typedef int slazy_t; 13 | const slazy_t LID = 0; 14 | // apply a <- b 15 | slazy_t combine_lazy(slazy_t a, slazy_t b){ 16 | return a+b; 17 | } 18 | void undoflip(){ 19 | ; 20 | } 21 | //////////////////////////////////////////////////////////// 22 | Snode *l = nullptr, *r = nullptr, *p = nullptr; 23 | scont_t content; int no = 0; 24 | snode_t val; 25 | slazy_t lazy = LID; bool doflip = false; 26 | int cnt = 1; 27 | 28 | Snode(scont_t c): content(c) {val = leaf_val(content);} 29 | 30 | // push, pull, and query 31 | Snode* refresh(){ 32 | val = leaf_val(content), cnt = 1; 33 | if(l) l->prop(), val = combine(l->val, val), cnt += l->cnt; 34 | if(r) r->prop(), val = combine(val, r->val), cnt += r->cnt; 35 | return this; 36 | } 37 | void lazy_add(slazy_t x){ 38 | lazy = combine_lazy(lazy, x); 39 | } 40 | Snode* flip(){doflip = !doflip; return this;} 41 | Snode* prop(){ 42 | if(doflip){ 43 | if(l) l->flip(); 44 | if(r) r->flip(); 45 | swap(l, r), undoflip(), doflip = false; 46 | } 47 | if(lazy != LID){ 48 | if(l) l->lazy_add(lazy); 49 | if(r) r->lazy_add(lazy); 50 | unlazy(), lazy = LID; 51 | } 52 | return this; 53 | } 54 | 55 | // helper funcs 56 | bool is_root(){return !p || (this != p->l && this != p->r);} 57 | bool is_left(){ 58 | assert(!p || p->lazy == LID); 59 | return p && p->l == this; 60 | } 61 | Snode *ch(bool left){ 62 | assert(lazy == LID); 63 | return left? l : r; 64 | } 65 | }; 66 | 67 | template 68 | struct Splay{ 69 | int n; 70 | Node *root; 71 | vector nodes; 72 | 73 | Splay(vector conts): n(sz(conts)){ 74 | root = new Node(0); 75 | for(int i=0; i<=n; i++){ 76 | Node *s = new Node(i=0; i--) nodes[i]->refresh(); 81 | root->refresh(); 82 | } 83 | 84 | // DO NOT USE THESE IN CLIENT CODES!!! 85 | void setpar(Node *par, Node *son, bool left){ 86 | if(son) son->p = par; 87 | if(left) par->l = son; 88 | else par->r = son; 89 | } 90 | void rotate(Node *x){ 91 | Node *p = x->p, *q = p->is_root() ? nullptr : p->p; 92 | if(q) q->prop(); 93 | p->prop(), x->prop(); 94 | bool xdir = (x == p->l); 95 | if(q) setpar(q, x, (p == q->l)); 96 | else x->p = nullptr, root = x; 97 | setpar(p, x->ch(!xdir), xdir), setpar(x, p, !xdir); 98 | p->refresh(), x->refresh(); 99 | } 100 | 101 | // splay methods. k, l, r are 1-indexed 102 | Node* splay(Node *x){ 103 | while(!x->is_root()){ 104 | Node *p = x->p, *q = p->is_root() ? nullptr : p->p; 105 | if(q) rotate((x == p->l) == (p == q->l) ? p : x); 106 | rotate(x); 107 | } 108 | return root = x; 109 | } 110 | Node* splay_kth(int k){ 111 | //assert(0 <= k && k <= n+1); 112 | Node *x = root->prop(); 113 | while(1){ 114 | while(x->l && x->l->cnt > k+1) x = x->l->prop(); 115 | if(x->l) k-= x->l->cnt; 116 | if(k-- < 0) break; 117 | x = x->r->prop(); 118 | } 119 | return splay(x); 120 | } 121 | int node_index(Node *x){return splay(x)->l->cnt;} 122 | 123 | // interval stuff 124 | Node* interval(int l, int r){ 125 | // l to r goes to root->r->l 126 | assert(0 <= l && l <= r && r < n); 127 | splay_kth(l-1); 128 | Node *x = root; 129 | root = x->r, root->p = NULL; 130 | splay_kth(r-l); 131 | setpar(x, root, false), root = x; 132 | return root->r->l->prop(); 133 | } 134 | void interval_update(int l, int r, typename Node::slazy_t x){ 135 | interval(l, r)->lazy_add(x); 136 | } 137 | void interval_flip(int l, int r){interval(l, r)->flip();} 138 | void interval_shift(int l, int r, int k){ 139 | int s = r-l+1; k = (k%s+s)%s; 140 | if(k == 0) return; 141 | interval_flip(l, r), interval_flip(l, l+s-k-1); 142 | interval_flip(l+s-k, r); 143 | } 144 | 145 | // insert and delete 146 | Node* insert(int k, typename Node::scont_t v){ 147 | n++; splay_kth(k); 148 | Snode *x = new Snode(v); 149 | if(root->l) root->l->p = x; 150 | x->l = root->l, x->r = NULL; 151 | setpar(root, x, true); 152 | return splay(x); 153 | } 154 | void remove(int k){ 155 | n--; splay_kth(k); 156 | Node *p = root->prop(); 157 | if(!p->l) root = p->r, root->p = nullptr; 158 | else if(!p->r) root = p->l, root->p = nullptr; 159 | else{ 160 | root = p->l, root->p = nullptr; 161 | Node *cur = root->prop(); 162 | while (cur->r) cur = cur->r->prop(); 163 | cur->r = p->r, p->r->p = cur; 164 | splay(cur); 165 | } 166 | delete p; 167 | } 168 | }; 169 | -------------------------------------------------------------------------------- /cpp/etc/max_sumarray.cpp: -------------------------------------------------------------------------------- 1 | template 2 | T max_sumarray(vector arr){ 3 | assert(!arr.empty()); 4 | T best = arr[0], cur = 0; 5 | for(T &x: arr){ 6 | cur+= x; 7 | best = max(best, cur); 8 | if(cur < 0) cur = 0; 9 | } 10 | return best; 11 | } 12 | -------------------------------------------------------------------------------- /cpp/geometry/circle.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jh05013/BOJ_algorithms/9d1d19badbf75e3285846c3444d7df952f62d710/cpp/geometry/circle.cpp -------------------------------------------------------------------------------- /cpp/geometry/point.cpp: -------------------------------------------------------------------------------- 1 | #define FR friend 2 | const double pi = 3.14159265358979323846264338327950288; 3 | TTT int sgn(T x){return (T(0)>(istream& is, Pnt& p){return is>>p.x>>p.y;} 15 | FR ostream& operator<<(ostream& os, CSP p){return os<<"("<(CSP a, CSP b){return b=(CSP a, CSP b){return b<=a;} 34 | FR T dot(CSP p, CSP q){return p.x*q.x + p.y*q.y;} 35 | FR T cross(CSP p, CSP q){return p.x*q.y - p.y*q.x;} 36 | 37 | // distance 38 | FR T sq(CSP p){return p.x*p.x + p.y*p.y;} 39 | FR double abs(CSP p){return sqrt(sq(p));} 40 | FR T distsq(CSP p, CSP q){return sq(p-q);} 41 | FR double dist(CSP p, CSP q){return sqrt(distsq(p, q));} 42 | 43 | // angle 44 | FR bool is_perp(CSP p, CSP q){return dot(p, q)==0;} 45 | FR double angle(CSP p, CSP q){ 46 | return acos(clamp(dot(p,q) / abs(p) / abs(q), -1.0, 1.0)); 47 | } 48 | FR double angle(CSP c, CSP p, CSP q){return angle(p-c, q-c);} 49 | FR double angle_ccw(CSP p, CSP q){ 50 | double theta = angle(p, q); 51 | return orient(p, Pnt(0,0), q) <= 0? theta : 2*pi - theta; 52 | } 53 | FR double angle_ccw(CSP c, CSP p, CSP q){return angle_ccw(p-c, q-c);} 54 | 55 | // orientation (<0 cw, =0 collinear, >0 ccw) 56 | FR T orient(CSP p, CSP q, CSP r){return cross(q-p, r-p);} 57 | FR int ccw(CSP p, CSP q, CSP r){return sgn(orient(p, q, r));} 58 | 59 | // transformation 60 | FR Pnt scale(CSP c, CSP p, T factor){return c + (p-c)*factor;} 61 | FR Pnt rot90(CSP p){return {-p.y, p.x};} 62 | FR Pnt rot90(CSP c, CSP p){return c + rot90(p-c);} 63 | /* TODO: FLOAT 64 | FR Pnt rot(CSP p, double theta){ 65 | double c = cos(theta), s = sin(theta); 66 | return {p.x*c - p.y*s, p.x*s + p.y*c}; 67 | } 68 | FR Pnt rot(CSP c, CSP p, double theta){return c + rot(p-c, theta);} */ 69 | #undef CSP 70 | }; -------------------------------------------------------------------------------- /cpp/geometry/polar_sort.cpp: -------------------------------------------------------------------------------- 1 | ////// Point polar sorting ////// 2 | // DEPENDENCY: POINT 3 | 4 | // ccw, tiebreaker is distance 5 | TTT void polar_sort(vector> &V, Pnt c){ 6 | auto pnt_half = [](Pnt p){ 7 | assert(p.x != 0 || p.y != 0); 8 | return p.y > 0 || (p.y == 0 && p.x < 0); 9 | }; 10 | for(Pnt &p: V) p-= c; 11 | sort(entire(V), [&](Pnt v, Pnt w){ 12 | return make_tuple(pnt_half(v), T(0), sq(v)) < 13 | make_tuple(pnt_half(w), cross(v,w), sq(w)); 14 | }); 15 | for(Pnt &p: V) p+= c; 16 | } 17 | 18 | TTT vector polar_sorted_halfplanes(vector> &P, const Pnt &c){ 19 | int n = sz(P), ri = 0; 20 | vector ans; 21 | for(int li=0; li EdgeIndex; 2 | template 3 | struct Dinic{ 4 | struct edge{ 5 | int source, target; T res, orig; int revid; 6 | T used(){return orig-res;} 7 | }; 8 | int n; 9 | vector> adj; vector dis, pnt; 10 | T INF; 11 | Dinic(int N, T INFTY): n{N}, adj(n+1), dis(n+1), pnt(n+1), INF(INFTY) {} 12 | EdgeIndex connect(int s, int e, T cap){ 13 | assert(0 <= s && s <= n && 0 <= e && e <= n); 14 | adj[s].push_back({s, e, cap, cap, sz(adj[e])}); 15 | adj[e].push_back({e, s, 0, 0, sz(adj[s])-1}); 16 | return {s, sz(adj[s])-1}; 17 | } 18 | edge& operator[](EdgeIndex eidx){return adj[eidx.first][eidx.second];} 19 | 20 | bool bfs(int src, int sink){ 21 | fill(entire(dis), 0), fill(entire(pnt), 0); 22 | queue Q({src}); dis[src] = 1; 23 | while(!Q.empty()){ 24 | int x = Q.front(); Q.pop(); 25 | for(auto &e: adj[x]) if(e.res > 0 && !dis[e.target]) 26 | dis[e.target] = dis[x]+1, Q.push(e.target); 27 | } 28 | return dis[sink] > 0; 29 | } 30 | T dfs(int x, int sink, T f){ 31 | if(x == sink) return f; 32 | for(; pnt[x] < sz(adj[x]); pnt[x]++){ 33 | edge e = adj[x][pnt[x]]; 34 | if(e.res > 0 && dis[e.target] == dis[x]+1){ 35 | T w = dfs(e.target, sink, min(f, e.res)); 36 | if(!w) continue; 37 | adj[x][pnt[x]].res-= w, adj[e.target][e.revid].res+= w; 38 | return w; 39 | } 40 | } 41 | return 0; 42 | } 43 | 44 | T send(int src, int sink){ 45 | T ret = 0; 46 | while(bfs(src, sink)){ 47 | T r; 48 | while((r = dfs(src, sink, INF))) ret+= r; 49 | } 50 | return ret; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /cpp/graph/mcmf.cpp: -------------------------------------------------------------------------------- 1 | typedef pair EdgeIndex; 2 | template 3 | struct MCMF { 4 | struct edge{ 5 | int source, target; T cost, res, orig; int revid; 6 | T used(){return orig-res;} 7 | }; 8 | int n; vector> adj; 9 | T INF; 10 | MCMF(int N, T INFTY): n(N), adj(n+1), INF(INFTY) {} 11 | 12 | EdgeIndex connect(int s, int e, T cap, T cost){ 13 | assert(0 <= s && s <= n && 0 <= e && e <= n); 14 | assert(s != e); 15 | adj[s].push_back(edge{s, e, cost, cap, cap, sz(adj[e]) }); 16 | adj[e].push_back(edge{e, s, -cost, 0, 0, sz(adj[s])-1}); 17 | return {s, sz(adj[s])-1}; 18 | } 19 | edge& operator[](EdgeIndex eidx){return adj[eidx.first][eidx.second];} 20 | // flow, cost 21 | pair aug(int s, int t, T lim){ 22 | vector> dist(n+1, {INF, 0}); 23 | vector from(n+1, -1), A(n+1); 24 | A[s] = 1; dist[s] = {0, INF}; 25 | queue Q; Q.push(s); 26 | while(!Q.empty()){ 27 | int v = Q.front(); A[v] = 0; Q.pop(); 28 | for(edge &e: adj[v]){ 29 | if(!e.res) continue; 30 | int next = e.target; T ncost = dist[v].first + e.cost; 31 | T nflow = min(dist[v].second, e.res); 32 | if(dist[next].first <= ncost) continue; 33 | dist[next] = {ncost, nflow}; 34 | from[next] = e.revid; 35 | if(!A[next]) A[next] = 1, Q.push(next); 36 | } 37 | } 38 | int p = t; T pcost = dist[p].first, flow = dist[p].second; 39 | if(!flow || (lim <= 0 && pcost >= 0)) return {0, 0}; 40 | if(lim > 0) flow = min(flow, lim); 41 | while(from[p] != -1){ 42 | int ne = from[p]; 43 | int np = adj[p][ne].target, fe = adj[p][ne].revid; 44 | adj[p][ne].res+= flow, adj[np][fe].res-= flow; 45 | p = np; 46 | } 47 | return {flow, pcost*flow}; 48 | } 49 | // flow, cost 50 | pair send(int s, int t){ 51 | T cost = 0, flow = 0; 52 | while(1){ 53 | auto [F, C] = aug(s, t, INF - flow); 54 | if(F <= 0) break; 55 | flow+= F, cost+= C; 56 | } 57 | return {flow, cost}; 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /cpp/graph/scc.cpp: -------------------------------------------------------------------------------- 1 | struct SCC{ 2 | int n; vector> adj; 3 | int sccnt = 0; // number of sccs 4 | vector scx; // idx (1-) of SCC for each vertex 5 | vector> sccs; // SCC, starts from [1] 6 | vector> dag; // graph of sccs 7 | vector loopcnt; // number of loops for each scc 8 | 9 | SCC(int N): n(N), adj(N), scx(N, -1) {} 10 | void connect(int a, int b){ 11 | assert(0 <= a && a < n && 0 <= b && b < n); 12 | adj[a].push_back(b); 13 | } 14 | void input(int m, int base=0){ 15 | int a,b; for(int i=0;i>a>>b; connect(a-base,b-base);} 16 | } 17 | void init(){ 18 | int cnt = 0; 19 | vector up(n, -1), visit(n, -1), stk; 20 | 21 | function dfs; 22 | dfs = [&](int v){ 23 | up[v] = visit[v] = cnt++; 24 | stk.push_back(v); 25 | for(int nxt: adj[v]){ 26 | if(visit[nxt] == -1) dfs(nxt), up[v] = min(up[v], up[nxt]); 27 | else if(scx[nxt] == -1) up[v] = min(up[v], visit[nxt]); 28 | } 29 | if(up[v] == visit[v]){ 30 | int t = -1; 31 | while(!stk.empty() && t != v){ 32 | t = stk.back(); stk.pop_back(); 33 | scx[t] = sccnt; 34 | } 35 | sccnt++; 36 | } 37 | }; 38 | for(int i=0; i 2 | T phi(T n){ 3 | if(n <= 1) return 0; 4 | T phi = n; 5 | for(T p=2; p*p<=n; p++) if(n%p == 0){ 6 | phi = phi/p*(p-1); 7 | while(n%p == 0) n/= p; 8 | } 9 | if(n > 1) phi = phi/n*(n-1); 10 | return phi; 11 | } 12 | -------------------------------------------------------------------------------- /cpp/math/fft.cpp: -------------------------------------------------------------------------------- 1 | const long double PI = acos(-1); 2 | template 3 | void FFT(vector> &A, bool inv){ 4 | int n = A.size(); 5 | for(int i=1, j=0; i>1; (j^=k)>= 1); 7 | if(i < j) swap(A[i], A[j]); 8 | } 9 | for(int i=1; i x(cos(w), sin(w)); 13 | for(int j=0; j y(1); 15 | for(int k=0; k z = A[i+j+k]*y; 17 | A[i+j+k] = A[j+k]-z, A[j+k]+= z; 18 | y*= x; 19 | } 20 | } 21 | } 22 | if(inv) for(int i=0; i 26 | vector polymul(vector X, vector Y){ 27 | int n, xy = sz(X)+sz(Y); 28 | for(n=1; n> A(n), B(n); 30 | for(int i=0; i res(xy); 36 | for(int i=0; i 2 | T floor_sum(T n, T m, T a, T b){ 3 | assert(0 <= n && 1 <= m); 4 | T ans = 0; 5 | if(a >= m || a < 0) ans+= (n-1)*n/2 * (a/m), a%= m; 6 | if(b >= m || b < 0) ans+= n * (b/m), b%= m; 7 | if(a == 0) return ans; 8 | T y = (a*n+b)/m, z = (a*n+b)%m; 9 | return ans + floor_sum(y, a, m, z); 10 | } 11 | -------------------------------------------------------------------------------- /cpp/math/harmonic_lemma.cpp: -------------------------------------------------------------------------------- 1 | // vector of {x, l, r} s.t n/i == x for i in [l, r] 2 | TTT vector> harmonic_floor(T n){ 3 | assert(n > 0); 4 | vector> ans; 5 | T i = 1; 6 | for(; n/i != n/(i+1); i++) ans.push_back({n/i, i, i}); 7 | for(T v = n/i; v >= 1; v--) ans.push_back({v, n/(v+1)+1, n/v}); 8 | return ans; 9 | } 10 | 11 | // vector of {x, l, r} s.t ceil(n/i) == x for i in [l, r] 12 | TTT T cdiv(T a, T b){return (a-1)/b+(T)1;} 13 | TTT vector> harmonic_ceil(T n){ 14 | assert(n > 0); 15 | vector> ans; 16 | T i = 1; 17 | for(; cdiv(n,i) != cdiv(n,i+1); i++) ans.push_back({cdiv(n,i), i, i}); 18 | for(T v = cdiv(n,i); v >= 2; v--) ans.push_back({v, cdiv(n,v), cdiv(n,v-1)-1}); 19 | return ans; 20 | } 21 | 22 | // {x, y, l, r} s.t n/i == x and m/i == y for i in [l, r] 23 | TTT vector> harmonic2_floor(T n, T m){ 24 | assert(n > 0 && m > 0); 25 | vector> ah = harmonic_floor(n), bh = harmonic_floor(m); 26 | vector> ans; 27 | int ai = 0, bi = 0; 28 | while(ai < sz(ah) && bi < sz(bh)){ 29 | auto [av, al, ar] = ah[ai]; 30 | auto [bv, bl, br] = bh[bi]; 31 | if(ar < br) ans.push_back({av,bv,al,ar}), ai++, bh[bi] = {bv,ar+1,br}; 32 | else if(ar == br) ans.push_back({av,bv,al,ar}), ai++, bi++; 33 | else ans.push_back({av,bv,bl,br}), bi++, ah[ai] = {av,br+1,ar}; 34 | } 35 | return ans; 36 | } 37 | -------------------------------------------------------------------------------- /cpp/math/linear_function.cpp: -------------------------------------------------------------------------------- 1 | TTT struct Linear{ 2 | T a, b; // ax+b 3 | Linear(): a(0), b(0) {} 4 | Linear(T B): a(0), b(B) {} 5 | Linear(T A, T B): a(A), b(B) {} 6 | 7 | friend istream& operator>>(istream& is, Linear& f){ 8 | return is >> f.a >> f.b; 9 | } 10 | friend ostream& operator<<(ostream& os, const Linear& f){ 11 | if(f.a.val == 0) return os< 0) os<<"+"; 16 | return os< 2 | T linear_modmin_rec(T a, T b, T N, T e){ 3 | if(e <= 10){ 4 | ll ans = b; 5 | for(ll x=1; x<=e; x++) ans = min(ans, (a*x+b)%N); 6 | return ans; 7 | } 8 | if(2*a > N) return linear_modmin_rec(N-a, (a*e+b)%N, N, e); 9 | if(a*e+b < N) return b; 10 | ll s = b + a*((N-b+a-1)/a) - N; 11 | return min(b, linear_modmin_rec(((-N)%a+a)%a, s, a, (a*e+b)/N - 1)); 12 | } 13 | 14 | // minimum (ax+b)%N for x = 0, ..., e 15 | template 16 | T linear_modmin(T a, T b, T N, T e){ 17 | assert(a >= 0 && b >= 0 && N > 0 && e >= 0); 18 | a%= N, b%= N; 19 | T g = __gcd(a, N); 20 | if(g != 1) return g * linear_modmin_rec(a/g, b/g, N/g, e) + b%g; 21 | return linear_modmin_rec(a, b, N, e); 22 | } 23 | -------------------------------------------------------------------------------- /cpp/math/modfactorial.cpp: -------------------------------------------------------------------------------- 1 | struct Modfact{ 2 | vector fact, ifact; 3 | Modfact(int n): fact(n+1), ifact(n+1){ 4 | fact[0] = 1; 5 | for(int i=1; i<=n; i++) fact[i] = fact[i-1] * (modint)i; 6 | ifact[n] = inv(fact[n]); 7 | for(int i=n-1; i>=0; i--) ifact[i] = ifact[i+1] * (modint)(i+1); 8 | } 9 | 10 | modint operator[](int i){return fact[i];} 11 | modint binom(int n, int k){ 12 | if(k > n) return 0; 13 | return fact[n] * ifact[k] * ifact[n-k]; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /cpp/math/modint.cpp: -------------------------------------------------------------------------------- 1 | const int MOD = 1000000007; 2 | struct modint{ 3 | int val; 4 | modint(): val{0} {} 5 | modint(const ll &v){ 6 | val = (-MOD <= v && v < MOD)? (int)v:(int)(v%MOD); 7 | if(val < 0) val+= MOD; 8 | } 9 | friend istream& operator>>(istream& is, modint& a){ 10 | ll v; is>>v; 11 | a.val = (-MOD <= v && v < MOD)? (int)v:(int)(v%MOD); 12 | if(a.val < 0) a.val+= MOD; 13 | return is; 14 | } 15 | friend ostream& operator<<(ostream& os, const modint& a){return os<=MOD) val-= MOD; return *this;} 22 | modint& operator-=(const modint& m){if((val-=m.val)<0) val+= MOD; return *this;} 23 | modint& operator*=(const modint& m){val = (int)((ll)val*m.val%MOD); return *this;} 24 | 25 | friend modint ipow(modint a, ll p){ 26 | assert(p >= 0); 27 | modint ans = 1; 28 | for(; p; p/=2, a*=a) if(p&1) ans*= a; 29 | return ans; 30 | } 31 | friend modint inv(const modint& a){ 32 | assert(a.val); 33 | return ipow(a, MOD-2); 34 | } 35 | modint& operator/=(const modint& m){return (*this)*= inv(m);} 36 | 37 | friend modint operator+(modint a, const modint& b){return a+= b;} 38 | friend modint operator-(modint a, const modint& b){return a-= b;} 39 | friend modint operator*(modint a, const modint& b){return a*= b;} 40 | friend modint operator/(modint a, const modint& b){return a/= b;} 41 | operator int64_t() const {return val;} 42 | }; -------------------------------------------------------------------------------- /cpp/math/modpoly.cpp: -------------------------------------------------------------------------------- 1 | const int MOD = 998244353; 2 | const int PRIMITIVE_ROOT = 3; 3 | 4 | struct modint{ 5 | int val; 6 | modint(): val{0} {} 7 | modint(const ll &v){ 8 | val = (-MOD <= v && v < MOD)? (int)v:(int)(v%MOD); 9 | if(val < 0) val+= MOD; 10 | } 11 | friend istream& operator>>(istream& is, modint& a){ 12 | ll v; is>>v; 13 | a.val = (-MOD <= v && v < MOD)? (int)v:(int)(v%MOD); 14 | if(a.val < 0) a.val+= MOD; 15 | return is; 16 | } 17 | friend ostream& operator<<(ostream& os, const modint& a){return os<=MOD) val-= MOD; return *this;} 24 | modint& operator-=(const modint& m){if((val-=m.val)<0) val+= MOD; return *this;} 25 | modint& operator*=(const modint& m){val = (int)((ll)val*m.val%MOD); return *this;} 26 | 27 | friend modint ipow(modint a, ll p){ 28 | assert(p >= 0); 29 | modint ans = 1; 30 | for(; p; p/=2, a*=a) if(p&1) ans*= a; 31 | return ans; 32 | } 33 | friend modint inv(const modint& a){ 34 | assert(a.val); 35 | return ipow(a, MOD-2); 36 | } 37 | modint& operator/=(const modint& m){return (*this)*= inv(m);} 38 | 39 | friend modint operator+(modint a, const modint& b){return a+= b;} 40 | friend modint operator-(modint a, const modint& b){return a-= b;} 41 | friend modint operator*(modint a, const modint& b){return a*= b;} 42 | friend modint operator/(modint a, const modint& b){return a/= b;} 43 | operator int64_t() const {return val;} 44 | }; 45 | 46 | struct modpoly{ 47 | vector P; 48 | 49 | //// INIT & BASIC 50 | modpoly(int n): P(n) {} 51 | modpoly(vector A): P(A) {} 52 | modint& operator[](int i){return P[i];} 53 | int size(){return sz(P);} 54 | bool empty(){return P.empty();} 55 | void normalize(){while(!empty() && P.back() == (modint)0) P.pop_back();} 56 | 57 | //// TRIVIAL OPS 58 | void resize(int n){P.resize(n);} 59 | modpoly resized(int n){ 60 | modpoly Q(n); 61 | for(int i=0; i>(istream &is, modpoly &p){ 69 | for(int i=0; i>p[i]; 70 | return is; 71 | } 72 | friend ostream& operator<<(ostream &os, const modpoly &p){ 73 | for(modint x:p.P) os<>1; (j^=k)>= 1); 112 | if(i < j) swap(P[i], P[j]); 113 | } 114 | modint RINV = ipow((modint)PRIMITIVE_ROOT, MOD-2); 115 | for(int i=1; i>1); 118 | for(int j=0; j multieval(vector xs){ 182 | vector tree; 183 | for(modint x: xs) tree.push_back(modpoly({-x, 1})); 184 | int i, ti; 185 | for(i=0; i+10; i-= 2, ti--){ 189 | tree[i] = tree[ti] % tree[i]; 190 | tree[i-1] = tree[ti] % tree[i-1]; 191 | } 192 | for(int j=0; j z_algo(string& s){ 2 | int n = s.size(), L=0, R=0; 3 | vector z(n); z[0] = n; 4 | for(int i=1; i R){ 6 | L = R = i; 7 | while(R < n && s[R-L] == s[R]) R++; 8 | z[i] = R-L; R--; 9 | continue; 10 | } 11 | int k = i - L; 12 | if(z[k] < R-i+1) z[i] = z[k]; 13 | else{ 14 | L = i; 15 | while(R < n && s[R-L] == s[R]) R++; 16 | z[i] = R-L; R--; 17 | } 18 | } 19 | return z; 20 | } 21 | 22 | TTT vector z_algo(vector& s){ 23 | int n = s.size(), L=0, R=0; 24 | vector z(n); z[0] = n; 25 | for(int i=1; i R){ 27 | L = R = i; 28 | while(R < n && s[R-L] == s[R]) R++; 29 | z[i] = R-L; R--; 30 | continue; 31 | } 32 | int k = i - L; 33 | if(z[k] < R-i+1) z[i] = z[k]; 34 | else{ 35 | L = i; 36 | while(R < n && s[R-L] == s[R]) R++; 37 | z[i] = R-L; R--; 38 | } 39 | } 40 | return z; 41 | } 42 | -------------------------------------------------------------------------------- /template.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | void OJize(){cin.tie(NULL);ios_base::sync_with_stdio(false);} 4 | 5 | typedef long long ll; 6 | const int IINF = 0x3f3f3f3f; 7 | const ll LINF = 0x3f3f3f3f3f3f3f3f; 8 | #define TTT template 9 | #define sz(X) (int)((X).size()) 10 | #define entire(X) X.begin(),X.end() 11 | 12 | int main(){OJize(); 13 | ; 14 | } 15 | --------------------------------------------------------------------------------