diff --git a/algorithms/graph/dinic.cpp b/algorithms/graph/dinic.cpp index e9fe5513f5da4d1b8647b92fa4d57cdfa56eb265..f45e94ff17c22c38c6ef17b5086aee75fa2f79b3 100644 --- a/algorithms/graph/dinic.cpp +++ b/algorithms/graph/dinic.cpp @@ -13,7 +13,9 @@ struct Dinic { vector<vector<Edge>> graph; Dinic(int N) : - N(N), depth(N), start(N), graph(N) {} + N(N), depth(N), + start(N), graph(N) + {} void add_edge(int u, int v, int c) { Edge forw = { v, 0, c, (int) graph[v].size() }; diff --git a/algorithms/graph/ford_fulkerson.cpp b/algorithms/graph/ford_fulkerson.cpp index 8562182dfc56136b23c454b8929676e018dec4a9..fb7a77f0ef01cacbe725a728affa4b2562fdd8c6 100644 --- a/algorithms/graph/ford_fulkerson.cpp +++ b/algorithms/graph/ford_fulkerson.cpp @@ -16,7 +16,9 @@ struct FordFulkerson { N(N), par(N), vis(N) { init(); } - void init() { fill(all(vis), 0); } + void init() { + fill(all(vis), 0); + } bool dfs(int s, int t) { vis[s] = true; diff --git a/algorithms/graph/hopcroft_karp.cpp b/algorithms/graph/hopcroft_karp.cpp index 542e9ac82ccec803d9e6628a4c8747b9f17b5b83..1897db3ab183c25add21a30561ea1b72cb04fffa 100644 --- a/algorithms/graph/hopcroft_karp.cpp +++ b/algorithms/graph/hopcroft_karp.cpp @@ -4,9 +4,10 @@ /// Space: O(V + E) /// /// Caution: -/// - Assumes 1-indexed vertices in graph. +/// - Assumes 0-indexed vertices in graph; +/// - The vertex enumeration on the left CAN be the same as the right. /// -/// Status: Tested (GCJ18-R2B) +/// Status: Tested (GCJ18-R2C) vector<int> graph[MAX]; @@ -21,51 +22,56 @@ struct HopcroftKarp { { init(); } void init() { - fill(all(matchL), 0); - fill(all(matchR), 0); + fill(all(matchL), -1); + fill(all(matchR), -1); } bool bfs() { queue<int> Q; - for (int l = 1; l <= L; ++l) - if (matchL[l] == 0) { + for (int l = 0; l < L; ++l) + if (matchL[l] == -1) { dist[l] = 0; Q.push(l); } else - dist[l] = inf; + dist[l] = -1; - dist[0] = inf; + bool ans = false; while (!Q.empty()) { int l = Q.front(); Q.pop(); - if (dist[l] < dist[0]) - for (auto r : graph[l]) - if (dist[matchR[r]] == inf) { - dist[matchR[r]] = dist[l] + 1; - Q.push(matchR[r]); - } + for (auto r : graph[l]) + if (matchR[r] == -1) + ans = true; + else if (dist[matchR[r]] == -1) { + dist[matchR[r]] = dist[l] + 1; + Q.push(matchR[r]); + } } - return (dist[0] != inf); + + return ans; } bool dfs(int l) { - if (l == 0) return true; + if (l == -1) + return true; + for (auto r : graph[l]) - if (dist[matchR[r]] == dist[l] + 1) + if (matchR[r] == -1 || dist[matchR[r]] == dist[l] + 1) if (dfs(matchR[r])) { matchR[r] = l; matchL[l] = r; return true; } - dist[l] = inf; + return false; } int run() { int ans = 0; while (bfs()) - for (int l = 1; l <= L; ++l) - if (matchL[l] == 0 && dfs(l)) + for (int l = 0; l < L; ++l) + if (matchL[l] == -1 && dfs(l)) ans++; + return ans; } }; diff --git a/algorithms/graph/kosaraju.cpp b/algorithms/graph/kosaraju.cpp index dd9b98f5a8208c93709b1842fa69d70e6741e703..22a9f83b1e213fe9cb28ab4767f5a8489c563f05 100644 --- a/algorithms/graph/kosaraju.cpp +++ b/algorithms/graph/kosaraju.cpp @@ -15,7 +15,9 @@ struct Kosaraju { N(N), vis(N) { init(); } - void init() { fill(all(vis), 0); } + void init() { + fill(all(vis), 0); + } void dfs(int x) { vis[x] = true; @@ -35,7 +37,6 @@ struct Kosaraju { int run() { int scc = 0; - init(); for (int i = 0; i < N; ++i) if (!vis[i]) fill_stack(i); @@ -55,6 +56,7 @@ struct Kosaraju { scc++; } } + return scc; } }; diff --git a/algorithms/graph/min_cost_max_flow.cpp b/algorithms/graph/min_cost_max_flow.cpp index 101ab2ca58de0e44bcf01741ba3d9a0aa9aa6f2f..c8dd2bb0f8e3ee6aca0538feee0626a58faae444 100644 --- a/algorithms/graph/min_cost_max_flow.cpp +++ b/algorithms/graph/min_cost_max_flow.cpp @@ -61,13 +61,16 @@ struct MinCostMaxFlow { int flow = inf; for (int i = t; i != s; i = par[i]) flow = min(flow, edges[ind[i]].cap); + for (int i = t; i != s; i = par[i]) { edges[ind[i] ].cap -= flow; edges[ind[i]^1].cap += flow; } + min_cost += flow * dist[t]; max_flow += flow; } + return ii(min_cost, max_flow); } }; diff --git a/algorithms/graph/prim.cpp b/algorithms/graph/prim.cpp index 53c4f2253a46dd5713543a2649d43586370c6f36..cb3fc48d100e86149c9bbf2b466886c10c746752 100644 --- a/algorithms/graph/prim.cpp +++ b/algorithms/graph/prim.cpp @@ -37,6 +37,7 @@ struct Prim { pq.push(ii(-i.se, -i.fi)); } } + return ans; } }; diff --git a/algorithms/graph/steiner_tree.cpp b/algorithms/graph/steiner_tree.cpp index 829ac259083f0ad338e4259549691147fa84c7fe..073407be2167208c0bd99bd626d9c2b23b02b0aa 100644 --- a/algorithms/graph/steiner_tree.cpp +++ b/algorithms/graph/steiner_tree.cpp @@ -3,11 +3,11 @@ /// Description: /// A (minimum) Steiner tree is a tree that, given a graph G and a set of /// terminal vertices T (inside the graph), connects all vertices in T using -/// other vertices in G if necessary, minimizing the sum of weights of the +/// other vertices in G if necessary, ans minimizes the sum of weights of the /// included edges. \par -/// The algorithm works by using dynamic programming, where dp[i][mask] +/// The algorithm uses dynamic programming, where dp[i][mask] /// stores the value of a Steiner tree rooted at $i$ containing the terminal -/// nodes represented by the bits in bitmask. The algorithm iterates over all +/// nodes represented by the bits in $mask$. The algorithm iterates over all /// bitmasks, and, at each iteration $mask$, every pair of complementary subsets /// are tested and dp[i][mask] is updated with the value given by the /// combination of both trees. Then, still at step $mask$, dp[j][mask] is diff --git a/algorithms/graph/topological_sort.cpp b/algorithms/graph/topological_sort.cpp index dbaab2285e076034669fcc1f84ff0d21b04e17e1..95a73fe1aa6dea2019908765100be37645e80d45 100644 --- a/algorithms/graph/topological_sort.cpp +++ b/algorithms/graph/topological_sort.cpp @@ -14,7 +14,9 @@ struct TopologicalSort { N(N), vis(N) { init(); } - void init() { fill(all(vis), 0); } + void init() { + fill(all(vis), 0); + } bool dfs(int x) { vis[x] = 1; diff --git a/algorithms/graph/travelling_salesman.cpp b/algorithms/graph/travelling_salesman.cpp index c4e1c08c709d32f720b192ecab2b48303f546157..c64dce724cfadcb211473478e8a871540890f63d 100644 --- a/algorithms/graph/travelling_salesman.cpp +++ b/algorithms/graph/travelling_salesman.cpp @@ -1,7 +1,7 @@ /// Travelling Salesman /// /// Description: -/// Given a graph and an origin vertex, this algorithm return the shortest +/// Given a graph and an origin vertex, this algorithm returns the shortest /// possible route that visits each vertex and returns to the origin. \par /// The algorithm works by using dynamic programming, where dp[i][mask] /// stores the last visited vertex $i$ and a set of visited vertices diff --git a/algorithms/math/pollard_rho.cpp b/algorithms/math/pollard_rho.cpp index b520f3dd7615cb0dab1eb4b0ef8d981b6aa5e289..99239b17f187c00e82e23cbe001021dc1ad7a853 100644 --- a/algorithms/math/pollard_rho.cpp +++ b/algorithms/math/pollard_rho.cpp @@ -13,7 +13,7 @@ ll pollard(ll n) { if (n % 2 == 0) return 2; - for (ll i = 2;; ++i) { + for (ll i = 2; ; ++i) { ll x = i, y = f(x), p; while ((p = __gcd(n + y - x, n)) == 1) x = f(x), y = f(f(y)); diff --git a/algorithms/string/aho_corasick.cpp b/algorithms/string/aho_corasick.cpp index f5c29f2cf1c916493dabcb4f7a39af079a7f6b30..b6aaa36efb1d1677d6661a76380789f539c66f53 100644 --- a/algorithms/string/aho_corasick.cpp +++ b/algorithms/string/aho_corasick.cpp @@ -10,7 +10,6 @@ /// Caution: /// - Match might not find all occurences when repeated strings are given (fix with map) -// *: Use only if "match_all" is necessary struct AhoCorasick { struct Node { vector<int> words; diff --git a/algorithms/string/kmp.cpp b/algorithms/string/kmp.cpp index 23581c22c7ed4c7bf164e092eb9da8dd818a9e09..85ff29fe4643394e09614081a7efae5d1d28e687 100644 --- a/algorithms/string/kmp.cpp +++ b/algorithms/string/kmp.cpp @@ -16,7 +16,7 @@ struct KMP { { preprocess(); } void preprocess() { - patt[0] = 0; + pi[0] = 0; for (int i = 1, j = 0; i < patt.size(); ++i) { while (j > 0 && patt[i] != patt[j]) j = pi[j - 1]; diff --git a/algorithms/structure/hash_function.cpp b/algorithms/structure/hash_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4497b534301f69c8702ed2f259af88c328776a44 --- /dev/null +++ b/algorithms/structure/hash_function.cpp @@ -0,0 +1,28 @@ +/// Hash Function (splitmix64) +/// +/// Description: +/// The default hash function for unordered\_map in C++ is not reliable when +/// it comes to non-random input (i.e. input designed to cause collisions, +/// such as multiples of a specific prime). This custom hash function solves +/// this problem (https://codeforces.com/blog/entry/62393). +/// +/// Time: O(1) +/// Space: O(n) + +struct CustomHash { + static uint64_t splitmix64(uint64_t x) { + x += 0x9e3779b97f4a7c15; + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; + x = (x ^ (x >> 27)) * 0x94d049bb133111eb; + return x ^ (x >> 31); + } + + size_t operator()(uint64_t x) const { + static const uint64_t FIXED_RANDOM = chrono::steady_clock::now() + .time_since_epoch() + .count(); + return splitmix64(x + FIXED_RANDOM); + } +}; + +unordered_map<ll,int,CustomHash> M; diff --git a/algorithms/structure/sparse_table.cpp b/algorithms/structure/sparse_table.cpp index 841f9ca24b3ca4a64f773e2377ea45a6860ef2b5..3d08456b08952ff570515a00e7a61e6e40c281a7 100644 --- a/algorithms/structure/sparse_table.cpp +++ b/algorithms/structure/sparse_table.cpp @@ -38,7 +38,7 @@ struct SparseTable { table[i][j] = func(table[i][j-1], table[i+(1<<(j-1))][j-1]); } - ll query(int l, int r) { + T query(int l, int r) { int j = log[r - l + 1]; return func(table[l][j], table[r - (1<<j) + 1][j]); } diff --git a/caderno.pdf b/caderno.pdf index f671b4a0e7e53af116e9af61625c66aa25f4e51e..6f3e97c4cb78c2cd65a23c9b20a96dbf2f81cf99 100644 Binary files a/caderno.pdf and b/caderno.pdf differ diff --git a/notebook/gen_latex.py b/notebook/gen_latex.py index 1474e8bafbc256fc504111ffce28e5056991ee99..4ef9259cb1ced819edb28aad3535d1cfed7053db 100644 --- a/notebook/gen_latex.py +++ b/notebook/gen_latex.py @@ -209,7 +209,9 @@ class LatexGenerator: self._write('\\tableofcontents\n') self._write('\\newpage\n\n') + self._write('\\begin{multicols*}{3}\n') self._gen_tree_latex(self.tree) + self._write('\\end{multicols*}\n') self._write('\\end{document}\n') @@ -247,12 +249,12 @@ class LatexGenerator: # Generates LaTeX for entire tree recursively. def _gen_tree_latex(self, sub, path = '', depth = 0): if type(sub) == list: - self._write('\\begin{multicols}{' + self._multicol(path) + '}\n') + #self._write('\\begin{multicols*}{' + self._multicol(path) + '}\n') for i in sub: source = self.SourceFile(path + i) self._gen_title_latex(source.name, depth) self._gen_code_latex(source) - self._write('\\end{multicols}\n') + #self._write('\\end{multicols*}\n') else: for i in sub: self._gen_title_latex(self._parse_dir_name(i), depth) diff --git a/notebook/header.tex b/notebook/header.tex index 52335f0c892649b408556c04747b546d38ebae11..e705c1273350b123dcef556a4b3b33b0e1295056 100644 --- a/notebook/header.tex +++ b/notebook/header.tex @@ -38,8 +38,8 @@ bottom=5mm, } -% Set sizes for *[sub]section -\titleformat*{\subsubsection}{\large\bfseries} +% Set sizes for [*sub]section +\titleformat*{\subsubsection}{\normalsize\bfseries} \titleformat*{\subsection}{\Large\bfseries} \titleformat*{\section}{\LARGE\bfseries}