diff --git a/caderno.pdf b/caderno.pdf index df4efc6e241440cbb102cc7850d3e8487d05652a..4b60aff95fa63be0f9c9d35e203505322483f7a7 100644 Binary files a/caderno.pdf and b/caderno.pdf differ diff --git a/caderno/caderno.tex b/caderno/caderno.tex index 0e3a8e4ffd203ea7a4224774beac4a83d383caa2..1444998d3504c3d90635f11e8c6c9f4148ab0aca 100644 --- a/caderno/caderno.tex +++ b/caderno/caderno.tex @@ -368,6 +368,11 @@ para $a$ e $m$ coprimos. \importsource{stdtlca.h} \subsection{Empar. máximo bipartido -- Kuhn} +\begin{tabular}{l} + \hline + As partes tem enumerações distintas + \\ \hline +\end{tabular} \importsource{kuhn.h} \subsection{Empar. máximo bipartido -- Hopcroft} @@ -386,7 +391,8 @@ para $a$ e $m$ coprimos. \subsection{Triângulo de Pascal} \importsource{pascal-triangle.h} -\subsection{2-SAT*} +\subsection{2-SAT} +\importsource{2-sat.h} \subsection{Inclusão-Exclusão} \importsource{inclusion-exclusion.h} @@ -397,7 +403,11 @@ para $a$ e $m$ coprimos. \subsection{Mínimo excluído} \importsource{mex.h} -\subsection{Nímero*} +\subsection{Nímero (Números de Grundy)} +\importsource{grundy.h} + +\subsection{Jogo de Nim} +\importsource{nim.h} \subsection{Euclides estendido/inv. multiplicativo} \begin{tabular}{l} @@ -421,7 +431,13 @@ ax + by = c \end{align*} \importsource{diophantine.h} -\subsection{Multiplicação -- Karatsuba*} +\subsection{Multiplicação -- Karatsuba} +\begin{tabular}{l} + \hline + $\bigO(n^{\log_3 n})$ \\ +\hline +\end{tabular} +\importsource{karatsuba.h} \subsection{Números de Catalão} \importsource{catalan.h} @@ -490,33 +506,55 @@ ax + by = c \end{tabular} \importsource{linearsieve.h} -\subsection{Exponenciação binária*} +\subsection{Exponenciação binária} \importsource{binary-pow.h} -\subsection{Exponenciação de matrizes*} -\importsource{matrix-mult.cpp} - -\subsection{Miller-Rabin*} +\subsection{Miller-Rabin} +\importsource{miller-rabin.h} -\subsection{Pollard Rho*} +\subsection{Pollard Rho} +\begin{tabular}{l} + \hline + $\bigO(n^{1/4})$ \\ +\hline +\end{tabular} +\importsource{pollardrho.h} -\subsection{Teorema chinês do resto*} +\subsection{Fibonacci} +\importsource{fibonacci.h} -\subsection{Fibonacci*} +\subsection{Teorema chinês do resto} +\begin{tabular}{l} + \hline + $\bigO(t \lg(m_1 m_2 \ldots m_t))$ \\ +\hline +\end{tabular} +\importsource{crt.h} -\subsection{Teorema chinês do resto generalizado*} +\subsection{Teorema chinês do resto generalizado} +\begin{tabular}{l|l} + \hline + $\bigO(t \lg(m_1 m_2 \ldots m_t))$ & + Infinitas soluções $\pm \text{lcm}(m_1m_2\ldots m_t)$ + \\ \hline +\end{tabular} +\importsource{noncoprimecrt.h} \section{Strings} \subsection{Árvore de sufixos} -\importsource{suffix-tree.h} +\importsource{st.h} -\subsection{Aho-Corasick*} +\subsection{Aho-Corasick} \importsource{acs.h} -\subsection{Algoritmo Z*} +\subsection{Autômato de Sufixo} +\importsource{saut.h} + +\subsection{Algoritmo Z} +$z[i]$ é o tamanho da maior string que é ao mesmo tempo, um prefixo de $s$ e um prefixo do sufixo de $s$ começando em $i$. -\subsection{Autômato de Sufixo*} +\importsource{z.h} \subsection{KMP} \begin{tabular}{l|l} @@ -527,14 +565,17 @@ ax + by = c \end{tabular} \importsource{kmp.h} -\subsection{Autômato KMP*} +\subsection{Autômato KMP} +\importsource{kmp-automaton.h} \subsection{Rabin-Karp} \importsource{rabinkarp.h} -\subsection{Vetor de sufixos*} +\subsection{Vetor de sufixos} +\importsource{sa.h} -\subsection{Vetor de sufixos com ordenação por contagem*} +\subsection{Vetor de sufixos radix} +\importsource{sar.h} \subsection{Trie} \importsource{trie.h} @@ -560,21 +601,32 @@ ax + by = c \end{tabular} \importsource{graham.h} -\subsection{Interseção de retângulos*} +\subsection{Interseção de retângulos} +\importsource{rectangle-intersection.h} -\subsection{Polígono é convexo?*} +\subsection{Ponto dentro do polígono?} +\importsource{isinsidepoly.h} -\subsection{Ponto dentro do polígono?*} +\subsection{Ponto dentro do polígono convexo?} +\importsource{isinsidepolyconvex.h} -\subsection{Área de polígono*} +\subsection{Área de polígono} +\importsource{polyarea.h} -\subsection{Área de polígono de pontos inteiros*} +\subsection{Pontos inteiros no polígono} +\begin{align*} +A = i + b/2 - 1 +\end{align*} +\importsource{latticepoints.h} -\subsection{Distância de segmento e segmento*} +\subsection{Segmento} +\importsource{seg.h} -\subsection{Distância de ponto e segmento*} +\subsection{Ponto e segmento} +\importsource{pointseg.h} -\subsection{Intersecção de segmento*} +\subsection{Segmento e segmento} +\importsource{segseg.h} \subsection{Árvore KD} \importsource{kd-tree.h} @@ -587,8 +639,6 @@ ax + by = c \section{Problemas} \subsection{Rainhas no tabuleiro*} -\subsection{Jogo de Nim*} - \subsection{Soma em subvetor*} \subsection{Remoção de valores com deque*} @@ -617,8 +667,8 @@ ax + by = c \subsection{PD de perfil quebrado*} -\subsection{Busca binária*} -\importsource{binary-search.cpp} +\subsection{Busca binária} +\importsource{bs.h} \subsection{Busca binária diferentona*} diff --git a/fontes/2-sat.h b/fontes/2-sat.h new file mode 100644 index 0000000000000000000000000000000000000000..41a938dcf42ef914a034be5f112105fe89f9ef0d --- /dev/null +++ b/fontes/2-sat.h @@ -0,0 +1,47 @@ +vector<vector<int>> g (2*N), g_t (2*N); +vector<int> rep (2*N), vis (2*N); +vector<bool> val (N); +stack<int> sinks; +int cts = 0; + +void fill_stack(int u) { + if (vis[u] == cts) { return; } + vis[u] = cts; + for (int v : g[u]) + fill_stack(v); + sinks.push(u); +} + +void mark_component(int u, int r) { + if (vis[u] == cts) { return; } + vis[u] = cts; rep[u] = r; + for (int v : g_t[u]) + mark_component(v, r); +} + +int solve2sat(int n) { + cts++; + for (int u = 0; u < 2*n; u++) { fill_stack(u); } + cts++; + int c = 0; + while (!sinks.empty()) { + int u = sinks.top(); sinks.pop(); + mark_component(u, c++); + } + for (int u = 0; u < n; u++) { + if (rep[2*u] == rep[2*u+1]) + return false; + val[u] = rep[2*u] > rep[2*u+1]; + } + return true; +} + +void add_implies(int a, bool na, int b, bool nb) { + a = 2*a+na; b = 2*b+nb; + g[a].push_back(b); g_t[b].push_back(a); +} + +void add_disj(int a, bool na, int b, bool nb) { + add_implies(a, !na, b, nb); + add_implies(b, !nb, a, na); +} diff --git a/fontes/angular-sweep.h b/fontes/angular-sweep.h index 0eee34be1519a0230ae60ff3646f7a1a66b26444..99a756699ab6c09c453951866ac19c7889be8a9b 100644 --- a/fontes/angular-sweep.h +++ b/fontes/angular-sweep.h @@ -1,4 +1,4 @@ -int get_points_inside (int i, double r, int n) { +int get_points_inside(int i, double r, int n) { vector<double> ang; for (int j = 0; j < n; j++) if (i != j && d[i][j] <= 2*r) { diff --git a/fontes/binary-pow.h b/fontes/binary-pow.h index 537f1481fadbe720902d3d4e05e96259af57e3e6..f9e74e7143fee75941a6bc04763e2f501d2f4e30 100644 --- a/fontes/binary-pow.h +++ b/fontes/binary-pow.h @@ -1,7 +1,7 @@ -ll fast_pow (ll& res, ll a, ll e) { +ll binary_pow(ll& res, ll a, ll e) { if (e == 0) { return res = 1; } if (e == 1) { return res = a; } - /* ll res = */ fast_pow(res, a, e/2); + /* ll res = */ binary_pow(res, a, e/2); res = res * res; if (e % 2) res = res * a; return res; diff --git a/fontes/binary-search.cpp b/fontes/bs.h similarity index 71% rename from fontes/binary-search.cpp rename to fontes/bs.h index 35161a1a58d3018c335291a1b4230aacc1f792f0..d761a7d724b9b576a769ef5208cca47b096707cd 100644 --- a/fontes/binary-search.cpp +++ b/fontes/bs.h @@ -1,6 +1,6 @@ -int binary_search (int lo, int hi) { +ll binary_search(ll lo, ll hi) { while (lo < hi) { - int mid = lo + (hi-lo) / 2; + ll mid = lo + (hi-lo) / 2; if (P(mid)) { hi = mid; } else { diff --git a/fontes/chinese-remainder-theorem.cpp b/fontes/chinese-remainder-theorem.cpp deleted file mode 100644 index f187f3e96a2dba49c93339e00b5bf8fa1fad10d6..0000000000000000000000000000000000000000 --- a/fontes/chinese-remainder-theorem.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// O(t lg lcm(m1, m2, ... m_t)) -// Infinitely many solutions can be found by +/- lcm(m1, m2, ..) x - -ll norm(ll a, ll b) { - a %= b; - return (a < 0) ? a + b : a; -} - -pair<ll,ll> crt_single(ll a, ll n, ll b, ll m) { - gans e = ext_gcd(n, m); - - if ((a - b) % e.d != 0) - return {-1,-1}; // No solution - - ll lcm = (m/e.d) * n; - ll ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, lcm); - return {norm(ans, lcm), lcm}; -} - -ll crt(vector<ll> a, vector<ll> m) { - ll ans = a[0]; - ll lcm = m[0]; - - int t = a.size(); - for (int i = 1; i < t; ++i) { - auto ss = crt_single(ans, lcm, a[i], m[i]); - if (ss.first == -1) - return -1; // No solution - - ans = ss.first; - lcm = ss.second; - } - - return ans; -} diff --git a/fontes/crt.h b/fontes/crt.h new file mode 100644 index 0000000000000000000000000000000000000000..266a3a2fbf715c95cb94ef62bd7e0e68dcf3ca80 --- /dev/null +++ b/fontes/crt.h @@ -0,0 +1,9 @@ +ll crt(vector<ll> a, vector<ll> m, int t) { + ll p = 1; for (ll& mi : m) { p *= mi; } + ll ans = 0; + for (int i = 0; i < t; i++) { + ll pp = p / m[i]; + ans = (ans + ((a[i] * inv(pp, m[i])) % p * pp) % p) % p; + } + return ans; +} diff --git a/fontes/fibonacci.h b/fontes/fibonacci.h new file mode 100644 index 0000000000000000000000000000000000000000..419312c5a4944ae963f92c38c428a2222a4c3583 --- /dev/null +++ b/fontes/fibonacci.h @@ -0,0 +1,19 @@ +using mat = vector<vector<ll>>; + +void mat_mul(mat& res, mat a) { mat b = res; + for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) + res[i][j] = ((a[i][0]*b[0][j]) % M + + (a[i][1]*b[1][j]) % M) % M; +} + +void fast_pow(mat& res, mat a, int b) { + if (b == 1) { res = a; return; } + fast_pow(res, a, b/2); + mat_mul(res, res); if (b % 2) { mat_mul(res, a); } +} + +int fibonacci(int n) { + mat x {{ 1, 1 }, { 1, 0 }}; + fast_pow(x, x, n); + return x[0][0]; +} diff --git a/fontes/grundy.cpp b/fontes/grundy.cpp deleted file mode 100644 index 6c6c092207e0dc140bdb298ca0b0f60526c614c3..0000000000000000000000000000000000000000 --- a/fontes/grundy.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include <bits/stdc++.h> -using namespace std; -const int N = 1e6+15; -#include "mexset.h" -vector<int> g (N, -1); -int main() { - mex m (N); - for (int n = 0; n <= 1226; n++) { - if (n == 1 || n == 2) { g[n] = 0; continue; } - for (int i = 1; i <= n/2; i++) if (i != n-i) - m.insert_mex(g[i] ^ g[n-i]); - g[n] = m.get_reset_mex(); - } - int t; cin >> t; while (t--) { - int n; cin >> n; - if (n >= 1226) - cout << "first\n"; - else - cout << (g[n] != 0 ? "first" : "second") << "\n"; - } -} diff --git a/fontes/grundy.h b/fontes/grundy.h new file mode 100644 index 0000000000000000000000000000000000000000..6979766c3bb0e8ad49394c3ea9642a423f6f0a5d --- /dev/null +++ b/fontes/grundy.h @@ -0,0 +1,10 @@ +void grundy() { + vector<int> g (N, -1); + mex m (N); + for (int n = 0; n <= 1226; n++) { + if (n == 1 || n == 2) { g[n] = 0; continue; } + for (int i = 1; i <= n/2; i++) if (i != n-i) + m.insert_mex(g[i] ^ g[n-i]); + g[n] = m.get_reset_mex(); + } +} diff --git a/fontes/hopcroft.h b/fontes/hopcroft.h index ff08c1c758ef5dce60764032473bbf4e1c0b3eb5..da76bb88c76f96257f1148cb13fbdd5bc77e720c 100644 --- a/fontes/hopcroft.h +++ b/fontes/hopcroft.h @@ -1,3 +1,4 @@ +vector<vector<int>> g (L); vector<int> matchl (L, -1), matchr (R, -1); vector<int> dist (L); @@ -32,9 +33,9 @@ bool dfs(int l) { return false; } -int hopcroft(int l) { +int hopcroft(int ln) { int ans = 0; - while (bfs(l)) for (int u = 0; u < l; u++) - if (matchl[u] == -1 && dfs(u)) { ans++; } + while (bfs(ln)) for (int l = 0; l < ln; l++) + if (matchl[l] == -1 && dfs(l)) { ans++; } return ans; } diff --git a/fontes/isinsidepoly.h b/fontes/isinsidepoly.h new file mode 100644 index 0000000000000000000000000000000000000000..2d34a1bc9ce2b4bacb881f4b1739a4e6cdc6d75e --- /dev/null +++ b/fontes/isinsidepoly.h @@ -0,0 +1,13 @@ +int is_inside_poly(vector<pt>& ps, pt p, int strict) { + int n = ps.size(); + if (n < 3) { return false; } + int count = 0; + for (int i = 0; i < n; i++) { + int j = (i+1)%n; + if (on_segment(seg(ps[i], ps[j]), p)) + return strict; + count ^= (((p.py < ps[i].py) - (p.py < ps[j].py)) + * ord_ornt(seg(ps[i], ps[j]), p)) > 0; + } + return count; +} diff --git a/fontes/isinsidepolyconvex.h b/fontes/isinsidepolyconvex.h new file mode 100644 index 0000000000000000000000000000000000000000..4cff718a7e7a8c4242943f6f70b9e3da8803e783 --- /dev/null +++ b/fontes/isinsidepolyconvex.h @@ -0,0 +1,10 @@ +bool is_inside_poly(vector<pt>& ps, pt p) { + int n = ps.size(); + double theta = 0; + for (int i = 0; i < n; i++) { + theta += (seg_ornt(ps[i], ps[(i+1)%n], p) + >= 0 ? +1 : -1) + * angle(ps[i], p, ps[(i+1)%n]); + } + return abs(theta - 2*PI) < EPS; +} diff --git a/fontes/iterative-lazy-segment-tree.cpp b/fontes/iterative-lazy-segment-tree.cpp deleted file mode 100644 index a9cd9fea9d13aee21fdddd3a8c21f9e29641f392..0000000000000000000000000000000000000000 --- a/fontes/iterative-lazy-segment-tree.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#define N 1<<17 -#define LEFT 2*i -#define RIGH 2*i+1 -#define M (ta+tb)/2 - -struct segtree { - int n, h; - struct node t[2 * N]; - struct node_update d[N]; - struct node (*merge)(struct node*, struct node*); - struct node_update (*merge_upd)(struct node_update*, struct node_update*); - struct node (*apply_upd)(struct node*, struct node_update*); - bool (*upd_done)(struct node_update*); - void (*upd_clear)(struct node_update*); - - void init() { - irof(i, 0, n) t[i] = tr->merge(&t[LEFT], &t[RIGH]); - fori(i, 0, N) upd_clear(&d[i]); - } - - void apply (int p, struct node_update* upd) { - t[p] = apply_upd(t[p], upd); - if (p < n) d[p] = merge_upd(&d[p], upd); - } - - void build (int i) { - while (i > 1) { - i /= 2; - t[i] = OP(&t[LEFT], &tr->t[RIGH]); - t[i] = apply_upd(&t[p], &d[p]); - } - } - - void push (int p) { - irof(s, 0, h+1) { - int i = p >> s; - if (!upd_done(&d[i])) { - apply(tr, LEFT, &d[i]); - apply(tr, RIGH, &d[i]); - upd_clear(&d[i]); - } - } - } - - void set_range (int l, int r, struct node_update* upd) { - l += n, r += n; - push(l); - push(r - 1); - int l0 = l, r0 = r; - for (; l < r; l /= 2, r /= 2) { - if (l & 1) apply(tr, l++, upd); - if (r & 1) apply(tr, --r, upd); - } - build(l0); - build(r0 - 1); - } - - T query_range (int l, int r) { - l += n, r += n; - push(l); push(r - 1); - T r1 = NEUTRAL, r2 = NEUTRAL; - for (; l < r; l /= 2, r /= 2) { - if (l & 1) r1 = OP(r1, t[l++]); - if (r & 1) r2 = OP(t[--r], r2); - } - return OP(r1, r2); - } -}; diff --git a/fontes/karatsuba.h b/fontes/karatsuba.h new file mode 100644 index 0000000000000000000000000000000000000000..d3ca7812bf8ed49036f288b68073c93891158a43 --- /dev/null +++ b/fontes/karatsuba.h @@ -0,0 +1,42 @@ +vector<ll> karatsuba(const vector<ll> &a, + const vector<ll> &b) { + int n = a.size(); + vector<ll> res(n + n); + + if (n <= 32) { + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + res[i + j] += a[i] * b[j]; + + return res; + } + + int k = n >> 1; + vector<ll> a1(a.begin(), a.begin() + k); + vector<ll> a2(a.begin() + k, a.end()); + vector<ll> b1(b.begin(), b.begin() + k); + vector<ll> b2(b.begin() + k, b.end()); + + vector<ll> a1b1 = karatsuba(a1, b1); + vector<ll> a2b2 = karatsuba(a2, b2); + + for (int i = 0; i < k; i++) + a2[i] += a1[i]; + for (int i = 0; i < k; i++) + b2[i] += b1[i]; + + vector<ll> r = karatsuba(a2, b2); + for (int i = 0; i < a1b1.size(); i++) + r[i] -= a1b1[i]; + for (int i = 0; i < a2b2.size(); i++) + r[i] -= a2b2[i]; + + for (int i = 0; i < r.size(); i++) + res[i + k] += r[i]; + for (int i = 0; i < a1b1.size(); i++) + res[i] += a1b1[i]; + for (int i = 0; i < a2b2.size(); i++) + res[i + n] += a2b2[i]; + + return res; +} diff --git a/fontes/kmp-automaton.cpp b/fontes/kmp-automaton.cpp deleted file mode 100644 index c7c95d3fde31045ceb2477d1e7c88f5a814d0638..0000000000000000000000000000000000000000 --- a/fontes/kmp-automaton.cpp +++ /dev/null @@ -1,17 +0,0 @@ -dp[i, c] = { - i+1, se i < |needle| && needle[i] == c - dp[pi(i), c], senão -} - -dp[i, c] = { - (i+1, 0), se i < |needle|-1 && needle[i] == c - (i+1, 1), se i == |needle| && needle[i] == c - (dp[pi(i), c], 0), senão -} - -Mesmo padrão: - -s_3 = s_1 + s_2 - -nxt_3[i] = nxt_2[nxt_1[i]] -occ_3[i] = occ_1[i] + occ_2[nxt_1[i]] diff --git a/fontes/kmp-automaton.h b/fontes/kmp-automaton.h new file mode 100644 index 0000000000000000000000000000000000000000..c07a6c82e53427c54f68536b435a13db9de5a935 --- /dev/null +++ b/fontes/kmp-automaton.h @@ -0,0 +1,16 @@ +void compute_automaton(string s, vector<vector<int>>& aut) { + s += '#'; + int n = s.size(); + vector<int> pi = pre(s); + aut.assign(n, vector<int>(26)); + for (int i = 0; i < n; i++) { + for (int c = 0; c < 26; c++) { + int j = i; + while (j > 0 && 'a' + c != s[j]) + j = pi[j-1]; + if ('a' + c == s[j]) + j++; + aut[i][c] = j; + } + } +} diff --git a/fontes/latticepoints.h b/fontes/latticepoints.h new file mode 100644 index 0000000000000000000000000000000000000000..07fcbf13d44a91555c65776390dcc5309971f058 --- /dev/null +++ b/fontes/latticepoints.h @@ -0,0 +1,15 @@ +ll lattice_points(vector<pt>& ps) { + ll b = 0; + for (int i = 0; i < n; i++) { + pt v = vec(ps[i], ps[(i+1)%n]); + if (v.py == 0) { + b += abs(v.px); + } else if (v.px == 0) { + b += abs(v.py); + } else { + b += gcd(abs(v.px), abs(v.py)); + } + } + + return poly_area(ps) - b/2 + 1; +} diff --git a/fontes/matrix-mult.cpp b/fontes/matrix-mult.cpp deleted file mode 100644 index cba2df4449a676019e195128464e12a3585f9f02..0000000000000000000000000000000000000000 --- a/fontes/matrix-mult.cpp +++ /dev/null @@ -1,8 +0,0 @@ -void nsq (vvll& res, vvll& n) { - int i = 0, j = 0; - ll x = (n[i][0]*res[0][j]) % mod + (n[i][1]*res[1][j]) % mod; - i = 0, j = 1; - ll y = (n[i][0]*res[0][j]) % mod + (n[i][1]*res[1][j]) % mod; - - res[0][0] = x % mod; res[0][1] = y % mod; -} diff --git a/fontes/maximum-bipartite-matching-hopcroft.cpp b/fontes/maximum-bipartite-matching-hopcroft.cpp deleted file mode 100644 index 96e9cc15bb54d2428c0a24c85024bfd2875180fe..0000000000000000000000000000000000000000 --- a/fontes/maximum-bipartite-matching-hopcroft.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// Maximum bipartite matching -// Hopcraft-Karp-Karzanov algorithm -// O(E*sqrt(V)) - -int L, R; -vector<vector<int>> graph (L); -vector<int> dist (L); -vector<int> matchL (L, -1), matchR (R, -1); - -bool bfs() { - queue<int> Q; - for (int l = 0; l < L; ++l) - if (matchL[l] == -1) { - dist[l] = 0; - Q.push(l); - } else - dist[l] = -1; - - bool ans = false; - while (!Q.empty()) { - int l = Q.front(); Q.pop(); - 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 ans; -} - -bool dfs(int l) { - if (l == -1) - return true; - - for (auto r : graph[l]) - if (matchR[r] == -1 || - dist[matchR[r]] == dist[l] + 1) - if (dfs(matchR[r])) { - matchR[r] = l; - matchL[l] = r; - return true; - } - - return false; -} - -int hopcroft() { - int ans = 0; - while (bfs()) - for (int l = 0; l < L; ++l) - if (matchL[l] == -1 && dfs(l)) - ans++; - - return ans; -} diff --git a/fontes/maximum-bipartite-matching-kuhn.cpp b/fontes/maximum-bipartite-matching-kuhn.cpp deleted file mode 100644 index c870c53131a964ffe929f5a199e7f81f2e8bd8ee..0000000000000000000000000000000000000000 --- a/fontes/maximum-bipartite-matching-kuhn.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Maximum bipartite matching -// Kuhn-Munkres or Hungarian algorithm -// O(V*E) - -// Bipartite, u and v are distinct enumerations -vector<vector<int>> graph (1e4+1); -vector<int> match (1e4+1, -1); -vector<bool> visited(1e4+1); - -int dfs(int u) { - if (visited[u]) { return 0; } - visited[u] = true; - - for (int v : graph[u]) { - if (match[v] == -1 || dfs(match[v])) { - match[v] = u; - return 1; - } - } - - return 0; -} - -int hungarian() { - int ans = 0; - for (int u = 0; u < n; u++) { - fill(visited.begin(), visited.end(), false); - ans += dfs(u); - } - return ans; -} diff --git a/fontes/miller-rabin.cpp b/fontes/miller-rabin.cpp deleted file mode 100644 index 72337f7dac13eb3145ed15f033df14a9923dd802..0000000000000000000000000000000000000000 --- a/fontes/miller-rabin.cpp +++ /dev/null @@ -1,26 +0,0 @@ -using ll = long long; -using i128 = __int128_t; - -ll fast_pow(ll a, ll e, ll m) { - if (e == 0) { return 1; } - if (e == 1) { return a; } - ll res = fast_pow(a, e/2, m); - res = (i128)res * res % m; - if (e % 2) res = (i128)res * a % m; - return res; -} - -bool is_prime(ll n) { - if (n < 2) { return false; } - int s = __builtin_ctzll(n - 1); - ll d = n >> s; - for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) { - if (n == a) { return true; } - ll p = fast_pow(a, d, n), i = s; - while (p != 1 && p != n - 1 && a % n && i--) - p = (i128)p * p % n; - if (p != n - 1 && i != s) - return false; - } - return true; -} diff --git a/fontes/miller-rabin.h b/fontes/miller-rabin.h new file mode 100644 index 0000000000000000000000000000000000000000..783e61e7d901c3f23094d27441065234f76afd54 --- /dev/null +++ b/fontes/miller-rabin.h @@ -0,0 +1,29 @@ +using ll = long long; using i128 = __int128_t; + +ll binary_pow(ll a, ll e, ll m) { + if (e == 0) { return 1; } + if (e == 1) { return a; } + ll res = binary_pow(a, e/2, m); + res = (i128)res * res % m; + if (e % 2) res = (i128)res * a % m; + return res; +} + +vector<int> witnesses = { + // primes from 2 to 37, enough for 64 bits + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37 +}; + +bool is_prime(ll n) { + if (n < 2) { return false; } + int s = __lg((n-1)&-(n-1)); + ll d = n >> s; + for (int a : witnesses) { + if (n == a) { return true; } + ll p = binary_pow(a, d, n), i = s; + while (p != 1 && p != n - 1 && a % n && i--) + p = (i128)p * p % n; + if (p != n - 1 && i != s) { return false; } + } + return true; +} diff --git a/fontes/misere.cpp b/fontes/misere.cpp deleted file mode 100644 index 6298ac9f551a9ef7d938624315ae44a41cadb5b7..0000000000000000000000000000000000000000 --- a/fontes/misere.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include <bits/stdc++.h> -using namespace std; -int main() { - cin.tie(0); - ios_base::sync_with_stdio(0); - int t; cin >> t; - while (t--) { - int n; cin >> n; - bool all_ones = true; - int res = 0; - for (int i = 0; i < n; i++) { - int x; cin >> x; res ^= x; - if (x != 1) { all_ones = false; } - } - if (all_ones) { res = n % 2 == 0; } - cout << (res != 0 ? "first" : "second") << "\n"; - } -} diff --git a/fontes/multiset.cpp b/fontes/multiset.cpp deleted file mode 100644 index 7270cefc702d4b78bb308f69f2c8821a103a5393..0000000000000000000000000000000000000000 --- a/fontes/multiset.cpp +++ /dev/null @@ -1,7 +0,0 @@ -map<int, int> freq; -for (int i = 0; i < n; i++) { - int x; cin >> x; freq[x]++; } -vector<pair<int, int>> bag; -for (auto f : freq) - bag.push_back(make_pair(f.second, f.first)); -sort(bag.rbegin(), bag.rend()); diff --git a/fontes/nim.cpp b/fontes/nim.cpp deleted file mode 100644 index fa6f8bbe35ad400abc60579a8baeb847ac35fed1..0000000000000000000000000000000000000000 --- a/fontes/nim.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <bits/stdc++.h> -using namespace std; -int main() { - int n; while (cin >> n) { - int g = 0; - vector<int> s (n); - for (int i = 0; i < n; i++) { - cin >> s[i]; g ^= s[i]; } - if (g == 0) { cout << "-1\n"; continue; } - int msb = (1<<__lg(g)); - for (int i = 0; i < n; i++) if (s[i]&msb) { - int t = s[i]^g; - cout << s[i]-t << " " << i+1 << "\n"; - break; - } - } -} diff --git a/fontes/nim.h b/fontes/nim.h new file mode 100644 index 0000000000000000000000000000000000000000..299647b743f78c22eee3f9c57a23244cc5503e5e --- /dev/null +++ b/fontes/nim.h @@ -0,0 +1,12 @@ +pair<int, int> solve_nim(vector<int> s) { + int n = s.size(), g = 0; + for (int i = 0; i < n; i++) + g ^= s[i]; + if (g == 0) { return {-1, -1}; } + int msb = 1<<__lg(g); + for (int i = 0; i < n; i++) if (s[i]&msb) { + int t = s[i]^g; + return { s[i]-t, i+1 }; + } + assert(0); +} diff --git a/fontes/noncoprimecrt.cpp b/fontes/noncoprimecrt.h similarity index 57% rename from fontes/noncoprimecrt.cpp rename to fontes/noncoprimecrt.h index 8ada3c3813001f80d52537185b86d3573bc30c7c..d09799492a82819d2d673ab5bf2cac40d0644d8f 100644 --- a/fontes/noncoprimecrt.cpp +++ b/fontes/noncoprimecrt.h @@ -1,15 +1,13 @@ -#include <bits/stdc++.h> -using namespace std; -using ll = long long; using vll = vector<ll>; -#include "extgcd.h" ll norm(ll a, ll b) { a %= b; return (a < 0) ? a + b : a; } + pair<ll, ll> crt_single(ll a, ll n, ll b, ll m) { ll x, y; ll g = extgcd(n, m, x, y); if ((a - b) % g) { return {-1, -1}; } ll lcm = (m/g) * n; return {norm(a + n*(x*(b-a)/g % (m/g)), lcm), lcm}; } -ll crt /* O(t lg m1*..*mt) */ (vll a, vll m, int t) { + +ll crt(vector<ll> a, vector<ll> m, int t) { ll ans = a[0], lcm = m[0]; for (int i = 1; i < t; ++i) { tie(ans, lcm) = crt_single(ans, lcm, a[i], m[i]); @@ -17,10 +15,3 @@ ll crt /* O(t lg m1*..*mt) */ (vll a, vll m, int t) { } return ans; } -int main() { - int t; while (cin >> t) { - vll a (t), m (t); - for (int i = 0; i < t; i++) { cin >> a[i] >> m[i]; } - cout << crt(a, m, t) << "\n"; - } -} diff --git a/fontes/point-compression.cpp b/fontes/point-compression.cpp deleted file mode 100644 index 72463c7507033ed0361455ffbd554b0deb01fe6f..0000000000000000000000000000000000000000 --- a/fontes/point-compression.cpp +++ /dev/null @@ -1,10 +0,0 @@ -void compress(int n, ll p, ll q) { - vector<pair<ll, int>> a (n); - for (int i = 0; i < n; i++) { - a[i] = make_pair(q*point[i].yy - p*point[i].xx, i); - } - sort(a.begin(), a.end()); - for (int i = 0; i < n; i++) { - f[a[i].second] = i; - } -} diff --git a/fontes/pointseg.h b/fontes/pointseg.h new file mode 100644 index 0000000000000000000000000000000000000000..c1dc5006525d21d7c471a34ed0a10f92bfe7fbb9 --- /dev/null +++ b/fontes/pointseg.h @@ -0,0 +1,12 @@ +pt point_in_seg(pt p, seg s) { + if (s.aa == s.bb) { return s.aa; } + double l = dot(vec(s.aa, p), vec(s)) / norm(vec(s)); + if (l < 0.0) { return s.aa; } + if (l > 1.0) { return s.bb; } + return s.aa + l*vec(s); +} + +bool on_segment(seg s, pt p) { + return cross(s.aa - p, s.bb - p) == 0 + && dot(s.aa - p, s.bb - p) <= 0; +} diff --git a/fontes/pollardrho.h b/fontes/pollardrho.h new file mode 100644 index 0000000000000000000000000000000000000000..1bf2067d84db7c7c321d5293938f900e989123d2 --- /dev/null +++ b/fontes/pollardrho.h @@ -0,0 +1,19 @@ +ll pollard(ll n) { + auto f = [n](ll x) { + return (fast_pow(x, x, n) + 1) % n; + }; + if (n % 2 == 0) { return 2; } + 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)); + if (p != n) { return p; } + } +} + +void factorize(vector<ll>& f, ll n) { + if (n == 1) { return; } + if (is_prime(n)) { f.push_back(n); return; } + ll x = pollard(n); + factorize(f, x); factorize(f, n/x); +} diff --git a/fontes/polyarea.h b/fontes/polyarea.h new file mode 100644 index 0000000000000000000000000000000000000000..b249e0f7858229ed539117e3202bef3c95039ea1 --- /dev/null +++ b/fontes/polyarea.h @@ -0,0 +1,7 @@ +double polygon_area(vector<pt>& ps) { + double area = cross(ps[ps.size()-1], ps[0]); + for (int i = 1; i < ps.size(); i++) { + area += cross(ps[i-1], ps[i]); + } + return area / 2.0; +} diff --git a/fontes/rectangle-intersection.cpp b/fontes/rectangle-intersection.cpp deleted file mode 100644 index 4b15b19f7cc8ed33d0b87f348a4b4054fc9f36f5..0000000000000000000000000000000000000000 --- a/fontes/rectangle-intersection.cpp +++ /dev/null @@ -1,7 +0,0 @@ -pt tl = pt(max(tl0.px, tl1.px), max(tl0.py, tl1.py)); -pt br = pt(min(br0.px, br1.px), min(br0.py, br1.py)); - -bool has_intersection = - (make_pair(tl.px, tl.py) <= make_pair(br.px, br.py)); -int area = (br-tl).px * (br-tl).py - diff --git a/fontes/rectangle-intersection.h b/fontes/rectangle-intersection.h new file mode 100644 index 0000000000000000000000000000000000000000..6f2f88f605c142a36119f039e7313b62675c4655 --- /dev/null +++ b/fontes/rectangle-intersection.h @@ -0,0 +1,5 @@ +bool has_intersection(pt tl0, pt br0, pt tl1, pt br1) { + pt tl = pt(max(tl0.px, tl1.px), max(tl0.py, tl1.py)); + pt br = pt(min(br0.px, br1.px), min(br0.py, br1.py)); + return make_pair(tl.px, tl.py) <= make_pair(br.px, br.py); +} diff --git a/fontes/suffix-array-sort.cpp b/fontes/sa.h similarity index 83% rename from fontes/suffix-array-sort.cpp rename to fontes/sa.h index 798a95bec4b57499a48d55dc3cc8ef6e02ae7d48..3c210b34b9f6511ad0dc97c1118b345b406e9c88 100644 --- a/fontes/suffix-array-sort.cpp +++ b/fontes/sa.h @@ -1,11 +1,10 @@ #define kk first #define ii second -// O(n lg^2 n) -vector<int> build_sa(int n, string s) { +pair<vector<int>, vector<int>> build_sa(string s) { + int n = s.size(); vector<int> sk (s.begin(), s.end()); - - vector<pair<ii, int>> a(n); + vector<pair<pair<int, int>, int>> a(n); for (int k = 1; k < n; k *= 2) { for (int i = 0; i < n; i++) a[i] = { { sk[i], sk[(i+k)%n] }, i }; @@ -14,10 +13,9 @@ vector<int> build_sa(int n, string s) { for (int i = 1, r = 0; i < n; i++) sk[a[i].ii] = a[i-1].kk == a[i].kk ? r : ++r; } - vector<int> sa (n); for (int i = 0; i < n; i++) { sa[i] = a[i].ii; } - return sa; + return make_pair(sa, sk); } vector<int> compute_lcp (vector<int> sa, vector<int> sk) { diff --git a/fontes/suffix-array-radix.cpp b/fontes/sar.h similarity index 71% rename from fontes/suffix-array-radix.cpp rename to fontes/sar.h index 8307ded4d8da574473e222c5b04a6ec71d3b899b..cb475a6fc6912f2fa810294817d3d804df7066a9 100644 --- a/fontes/suffix-array-radix.cpp +++ b/fontes/sar.h @@ -1,30 +1,26 @@ -vector<int> sk (n), sa (n); - -void build_sa(string s, int n) { - vector<ii> a (n); +pair<vector<int>, vector<int>> build_sa(string s, int n) { + vector<int> sk (n), sa (n); + vector<pair<int, int>> a (n); for (int i = 0; i < n; i++) { a[i] = { s[i], i }; } sort(a.begin(), a.end()); for (int i = 0; i < n; i++) { tie(sk[i], sa[i]) = a[i]; } - vector<int> nsk(n); for (int i = 1, r = 0; i < n; i++) nsk[sa[i]] = (sk[i-1] == sk[i] ? r : ++r); sk.swap(nsk); - for (int k = 1; k < n; k *= 2) { for (int i = 0; i < n; i++) { sa[i] = (sa[i]-k+n)%n; } - vector<int> nsa(n), cnt(n+1); for (int x : sk) { cnt[x+1]++; } for (int i = 1; i < n; i++) { cnt[i] += cnt[i-1]; } for (int x : sa) { nsa[cnt[sk[x]]++] = x; } sa.swap(nsa); - vector<int> nsk(n); for (int i = 1, r = 0; i < n; i++) nsk[sa[i]] = - ii(sk[sa[i-1]], sk[(sa[i-1]+k)%n]) == - ii(sk[sa[i-0]], sk[(sa[i-0]+k)%n]) ? r : ++r; + make_pair(sk[sa[i-1]], sk[(sa[i-1]+k)%n]) == + make_pair(sk[sa[i-0]], sk[(sa[i-0]+k)%n]) ? r : ++r; sk.swap(nsk); } + return make_pair(sa, sk); } diff --git a/fontes/saut.h b/fontes/saut.h new file mode 100644 index 0000000000000000000000000000000000000000..1802f4a3bb29e575bd830dbdaafb74d34ec2fb96 --- /dev/null +++ b/fontes/saut.h @@ -0,0 +1,62 @@ +int last = 0, sz = 1; +vector<int> len (2*N), lnk (2*N), acc (2*N); +vector<vector<int>> nxt (2*N, vector<int>(S)); +void add(int c) { + int cur = sz++; len[cur] = len[last]+1; + int p = last; last = cur; + for (; ~p && !nxt[p][c]; p = lnk[p]) + nxt[p][c] = cur; + if (!~p) { lnk[cur] = 0; return; } + int q = nxt[p][c]; + if (len[q] == len[p]+1) { lnk[cur] = q; return; } + int qq = sz++; len[qq] = len[p]+1; lnk[qq] = lnk[q]; + copy(nxt[q].begin(), nxt[q].end(), nxt[qq].begin()); + for (; ~p && nxt[p][c] == q; p = lnk[p]) + nxt[p][c] = qq; + lnk[cur] = lnk[q] = qq; +} + +void build(string& s) { + len[0] = 0, lnk[0] = -1; + for (char ch : s) { add(to_i(ch)); } + for (int u = last; u; u = lnk[u]) { acc[u] = 1; } +} + +vector<int> cnt (2*N); +vector<int> ord; +void reverse_topo(int u) { + cnt[u] = 1; + for (int c = 0; c < S; c++) if (nxt[u][c]) + if (!cnt[nxt[u][c]]) + reverse_topo(nxt[u][c]); + ord.push_back(u); +} +void process_count() { + for (int u : ord) { + cnt[u] = 0; + for (int c = 0; c < S; c++) if (nxt[u][c]) + cnt[u] += cnt[nxt[u][c]]; + if (acc[u]) { cnt[u]++; } + } +} + +int longest_common_substring(string& t) { + int u = 0, l = 0, ans = 0, pos = -1; + for (int i = 0; i < t.size(); i++) { + int c = t[i]; + while (u && !nxt[u][c]) { + u = lnk[u]; l = len[u]; + } + if (nxt[u][c]) { u = nxt[u][c]; l++; } + else { u = 0; l = 0; } + if (l > ans) { ans = l; pos = i; } + } + return ans; +} + +int search(string& t) { + int u = 0; for (auto c : t) { + u = nxt[u][to_i(c)]; + if (!u) { return 0; }} + return cnt[u]; +} diff --git a/fontes/seg.h b/fontes/seg.h new file mode 100644 index 0000000000000000000000000000000000000000..76171c0278bd7acd79c116f7da898d7fb9b2d65b --- /dev/null +++ b/fontes/seg.h @@ -0,0 +1,7 @@ +#define aa first +#define bb second +using seg = pair<pt, pt>; +pt vec(seg s) { return vec(s.aa, s.bb); } +int ord_ornt(seg s, pt c) { + return seg_ornt(s.aa, s.bb, c); +} diff --git a/fontes/segseg.h b/fontes/segseg.h new file mode 100644 index 0000000000000000000000000000000000000000..e7902e08a07ea97898ac04de07d0b2c7a376c1a9 --- /dev/null +++ b/fontes/segseg.h @@ -0,0 +1,19 @@ +bool intersects_seg(seg s, seg t) { + int o1 = ord_ornt(s, t.aa), o2 = ord_ornt(s, t.bb); + int o3 = ord_ornt(t, s.aa), o4 = ord_ornt(t, s.bb); + return ( + (o1 != o2 && o3 != o4) || + (o1 == 0 && on_segment(s, t.aa)) || + (o2 == 0 && on_segment(s, t.bb)) || + (o3 == 0 && on_segment(t, s.aa)) || + (o4 == 0 && on_segment(t, s.bb))); +} + +double distance_seg_seg(seg s, seg t) { + if (intersects_seg(s, t)) { return 0; } + double v1 = distance_seg_point(s.aa, t); + double v2 = distance_seg_point(s.bb, t); + double v3 = distance_seg_point(t.aa, s); + double v4 = distance_seg_point(t.bb, s); + return min({ v1, v2, v3, v4 }); +} diff --git a/fontes/suffix-tree.h b/fontes/st.h similarity index 100% rename from fontes/suffix-tree.h rename to fontes/st.h diff --git a/fontes/stair.cpp b/fontes/stair.cpp deleted file mode 100644 index 3ff33125cfe15916497281e1a0b46c32cf1442a2..0000000000000000000000000000000000000000 --- a/fontes/stair.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include <bits/stdc++.h> -using namespace std; -int main() { - int t; cin >> t; - while (t--) { - int n; cin >> n; - int ans = 0; - for (int i = 0; i < n; i++) { - int p; cin >> p; - if (i % 2) { ans ^= p; } - } - cout << (ans == 0 ? "second" : "first") << "\n"; - } -} diff --git a/fontes/suffix-automaton.cpp b/fontes/suffix-automaton.cpp deleted file mode 100644 index 1bfdd8d45033112895fb53248e3b096b0624843f..0000000000000000000000000000000000000000 --- a/fontes/suffix-automaton.cpp +++ /dev/null @@ -1,51 +0,0 @@ -struct suffix_automaton { - int last, sz; - vector<int> len, lnk, acc; - vector<vector<int>> nxt; - - suffix_automaton() : len(2*MAX), lnk(2*MAX), - acc(2*MAX), nxt(2*MAX, vector<int>(26)) {} - - void add(int c) { - int cur = sz++; - len[cur] = len[last]+1; - int p = last; - last = cur; - for (; ~p && !nxt[p][c]; p = lnk[p]) - nxt[p][c] = cur; - if (!~p) { lnk[cur] = 0; return; } - int q = nxt[p][c]; - if (len[q] == len[p]+1) { lnk[cur] = q; return; } - int qq = sz++; - len[qq] = len[p]+1; - lnk[qq] = lnk[q]; - copy(nxt[q].begin(), nxt[q].end(), nxt[qq].begin()); - for (; ~p && nxt[p][c] == q; p = lnk[p]) - nxt[p][c] = qq; - lnk[cur] = lnk[q] = qq; - } - - void build(string& s) { - last = 0, sz = 1; - len[0] = 0, lnk[0] = -1; - for (char ch : s) { add(ch-'A'); } - for (int u = last; u; u = lnk[u]) { acc[u] = 1; } - } - - int longest_common_substring(string& t) { - int u = 0, l = 0, ans = 0, pos = -1; - for (int i = 0; i < t.size(); i++) { - while (u && !nxt[u][t[i]-'A']) { - u = lnk[u]; l = len[u]; - } - if (nxt[u][t[i]-'A']) { - u = nxt[u][t[i]-'A']; - l++; - } else { - u = 0; l = 0; - } - if (l > ans) { ans = l; pos = i; } - } - return ans; - } -}; diff --git a/fontes/z.h b/fontes/z.h new file mode 100644 index 0000000000000000000000000000000000000000..6d014fa0ff263d7b6768ede2c0418e86dfcb9438 --- /dev/null +++ b/fontes/z.h @@ -0,0 +1,13 @@ +vector<int> z_function(string s) { + int n = (int)s.length(); + vector<int> z (n); + for (int i = 1, l = 0, r = 0; i < n; ++i) { + if (i <= r) + z[i] = min (r - i + 1, z[i - l]); + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) + ++z[i]; + if (i + z[i] - 1 > r) + l = i, r = i + z[i] - 1; + } + return z; +}