Latex
Latex
6 Dynamic Programming 17
6.1 Longest Increasing Subsequence . . . . . . . . . . . . . . . . . . . . . . . 17
6.2 Travelling Salesman Problem . . . . . . . . . . . . . . . . . . . . . . . . 17
6.3 Knapsack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.4 Divide & Conquer Optimization . . . . . . . . . . . . . . . . . . . . . . 19
7 Graphs 20
7.1 BFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.2 DFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3 TopoSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.4 Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.5 Minimum Spanning Tree (Kruskal & Prim) . . . . . . . . . . . . . . . . 22
Pablo Messina’s ICPC Notebook 2 C++ CHEAT SHEET - Página 2 de 40
1 C++ Template 29 ss >> y; // y = 12345678910
30
31 // 2) stoi, stoll
1 #pragma GCC optimize("Ofast") 32 string str_dec = "2001, A Space Odyssey";
2 #include <bits/stdc++.h> 33 string str_hex = "40c3";
3 using namespace std; 34 string str_bin = "-10010110001";
4 // defines 35 string str_auto = "0x7f";
5 #define rep(i,a,b) for(int i = a; i <= b; ++i) 36 int sz;
6 #define invrep(i,b,a) for(int i = b; i >= a; --i) 37 int i_dec = stoi(str_dec,&sz);
7 #define umap unordered_map 38 int i_hex = stoi(str_hex,0,16);
8 #define uset unordered_set 39 int i_bin = stoi(str_bin,0,2);
9 // typedefs; 40 int i_auto = stoi(str_auto,0,0);
10 typedef unsigned long long int ull; 41 cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
11 typedef long long int ll; 42 cout << str_hex << ": " << i_hex << ’\n’;
12 typedef vector<int> vi; 43 cout << str_bin << ": " << i_bin << ’\n’;
13 typedef pair<int,int> ii; 44 cout << str_auto << ": " << i_auto << ’\n’;
14 // ------------------------------- 45 // 2001, A Space Odyssey: 2001 and [, A Space Odyssey]
15 int main() { 46 // 40c3: 16579
16 ios::sync_with_stdio(false); 47 // -10010110001: -1201
17 cin.tie(0); cout.tie(0); 48 // 0x7f: 127
18 return 0; 49 string str = "8246821 0xffff 020";
19 } 50 int sz = 0;
51 while (!str.empty()) {
2 C++ Cheat Sheet 52
53
long long ll = stoll(str,&sz,0);
cout << str.substr(0,sz) << " interpreted as " << ll << ’\n’;
54 str = str.substr(sz);
1 /* ================================= */ 55 }
2 /* Input/Output with C++: cin & cout */ 56 // 8246821 interpreted as 8246821
3 /* ================================= */ 57 // 0xffff interpreted as 65535
4 58 // 020 interpreted as 16
5 // reading many lines of unknown length 59
13 67 /* ============================ */
14 // printing floating with fixed precision 68 /* C++ STRING UTILITY FUNCTIONS */
15 cout << setprecision(6) << fixed; 69 /* ============================ */
16 cout << 12312.12312355; 70
5 #define rep(i,a,b) for(int i=a; i<=b; i++) 59 int arr[5] = {1, 2, 3, 4, 5};
6 using namespace std; 60 v2.assign(arr, arr + 5); // v2 = {1, 2, 3, 4, 5}
7 61 v2.assign(arr, arr + 3); // v2 = {1, 2, 3}
8 //============================== 62
25 //===================================================== 79
14 // or 68 //==========================
15 unordered_map<string,float> m; 69 // unordered_map::operator=
16 m.emplace("a", 1.50); 70 //==========================
17 m.emplace("b", 2.10); 71 typedef unordered_map<string,string> stringmap;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 11 de 40
72 stringmap merge (stringmap a,stringmap b) { 22 // 1 10 20 30 30 20 2 3 4 5
73 stringmap temp(a); temp.insert(b.begin(),b.end()); return temp; 23 // ^
74 } 24 cout << "mylist contains:";
75 int main() { 25 for (int x : mylist) cout << ’ ’ << x;
76 stringmap first, second, third; 26 cout << ’\n’;
77 first = {{"AAPL","Apple"},{"MSFT","Microsoft"}}; // init list 27 // mylist contains: 1 10 20 30 30 20 2 3 4 5
78 second = {{"GOOG","Google"},{"ORCL","Oracle"}}; // init list 28
79 third = merge(first,second); // move 29 //=======
80 first = third; // copy 30 // ERASE
81 cout << "first contains:"; 31 //=======
82 for (auto& x: first) cout << " " << x.first << ":" << x.second; 32 // http://www.cplusplus.com/reference/list/list/erase/
83 cout << ’\n’; 33
84 return 0; 34 list<int> mylist;
85 } 35 list<int>::iterator it1,it2;
86 // first contains: MSFT:Microsoft AAPL:Apple GOOG:Google ORCL:Oracle 36 // set some values:
37 rep(i,1,9) mylist.push_back(i*10);
3.1.10 Deque 38 // 10 20 30 40 50 60 70 80 90
39 it1 = it2 = mylist.begin(); // ^^
1 // references: 40 advance (it2,6); // ^ ^
2 // http://www.cplusplus.com/reference/deque/deque/ 41 ++it1; // ^ ^
3 // https://www.geeksforgeeks.org/deque-cpp-stl/ 42
1 // Find the index of the first item that satisfies a predicate 55 int main () {
2 // over a range [i,j), i.e., from i to j-1 56 vector<int> v{10,20,30,30,20,10,10,20}; // 10 20 30 30 20 10 10 20
3 // If no such index exists, j is returned 57 sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
4 function binsearch(array, i, j) { 58 auto low = lower_bound (v.begin(), v.end(), 20); // ^
5 assert(i < j) // since the range is [i,j), then j must be > i 59 auto up = upper_bound (v.begin(), v.end(), 20); // ^
6 while (i < j) { 60 cout << "lower_bound at position " << (low- v.begin()) << ’\n’;
7 m = (i+j) >> 1; // m = (i+j) / 2; 61 cout << "upper_bound at position " << (up - v.begin()) << ’\n’;
8 if (predicate(array[m])) 62 return 0;
9 j = m 63 }
10 else 64
11 i = m + 1 65 // ------------------------------------------------
12 } 66 // Query: how many items are LESS THAN (<) value x
13 return i; // notice that i == j if the predicate is false for the whole range 67
16 // ----------------------------- 70 // ------------------------------------------------
17 // EXAMPLE 1: Integer Lowerbound 71 // Query: how many items are GREATER THAN (>) value x
18 // predicate(a, i, key) = (a[i] >= key) 72
3 /* ===================== */ 57 // ---------------------------------
4 58 // TOP-DOWN RECURSION (pseudo-code)
5 // -------------------------------------- 59
7 #define invrep(i,b,a) for (int i=b; i>=a; --i) 61 // move node u "k" levels up towards the root
8 62 // i.e. find the k-th ancestor of u
9 // General comments: 63 int raise(int u, int k) {
10 // * Both of these methods assume that we are working with a connected 64 for (int e = 0; k; e++, k>>=1) if (k&1) u = anc(u,e);
11 // graph ’g’ of ’n’ nodes, and that nodes are compactly indexed from 0 to n-1. 65 return u;
12 // In case you have a forest of trees, a simple trick is to create a fake 66 }
13 // root and connect all the trees to it (make sure to re-index all your nodes) 67
14 // * ’g’ need not be a ’tree’, DFS fill implictly find a tree for you 68 int lca(int u, int v) {
15 // in case you don’t care of the specific tree (e.g. if cycles are not important) 69 if (D[u] < D[v]) swap(u, v);
16 70 u = raise(u, D[u] - D[v]); // raise lowest to same level
17 // ------------------------------------------------------------ 71 if (u == v) return u; // same node, we are done
18 // METHOD 1: SPARSE TABLE - BINARY LIFTING (aka JUMP POINTERS) 72 // raise u and v to their highest ancestors below the LCA
19 // ------------------------------------------------------------ 73 invrep (e, maxe, 0) {
20 // construction: O(|V| log |V|) 74 // greedily take the biggest 2^e jump possible as long as
21 // query: O(log|V|) 75 // u and v still remain BELOW the LCA
22 // ** advantages: 76 if (anc(u,e) != anc(v,e)) {
23 // - the lca query can be modified to compute querys over the path between 2 nodes 77 u = anc(u,e), v = anc(v,e);
24 // - it’s possible to append new leaf nodes to the tree 78 }
25 79 }
26 struct LCA { 80 // the direct parent of u (or v) is lca(u,v)
27 vector<int> A, D; // ancestors, depths 81 return anc(u,0);
28 vector<vector<int>> *g; // pointer to graph 82 }
29 int n, maxe; // num nodes, max exponent 83
30 int& anc(int u, int e) { return A[e * n + u]; } 84 // distance between ’u’ and ’v’
31 int inline log2(int x) { return 31 - __builtin_clz(x); } 85 int dist(int u, int v) {
32 86 return D[u] + D[v] - 2 * D[lca(u,v)];
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.6 Lowest Commen Ancestor (LCA) Página 24 de 40
87 } 140 D[idx++] = depth;
88 // optimized version (in case you already computed lca(u,v)) 141 }
89 int dist(int u, int v, int lca_uv) { 142 }
90 return D[u] + D[v] - 2 * D[lca_uv]; 143 }
91 } 144
92 // get the node located k steps from ’u’ walking towards ’v’ 145 LCA(vector<vector<int>>& _g, int root) {
93 int kth_node_in_path(int u, int v, int k) { 146 g = &_g;
94 int lca_uv = lca(u,v); 147 n = _g.size();
95 if (D[u] - D[lca_uv] >= k) return raise(u, k); 148 H.assign(n, -1);
96 return raise(v, dist(u,v,lca_uv) - k); 149 E.resize(2*n);
97 } 150 D.resize(2*n);
98 151 idx = 0;
99 int add_child(int p, int u) { // optional 152 dfs(root, 0); // euler tour
100 // add to graph 153 int nn = idx; // <-- make sure you use the correct number
101 (*g)[p].push_back(u); 154 int maxe = log2(nn);
102 // update depth 155 DP.resize(nn * (maxe+1));
103 D[u] = D[p] + 1; 156 // build sparse table with bottom-up DP
104 // update ancestors 157 rep(i,0,nn-1) rmq(i,0) = i; // base case
105 anc(u,0) = p; 158 rep(e,1,maxe) { // general cases
106 rep (e, 1, maxe){ 159 rep(i, 0, nn - (1 << e)) {
107 p = anc(p,e-1); 160 // i ... i + 2 ^ (e-1) - 1
108 if (p == -1) break; 161 int i1 = rmq(i,e-1);
109 anc(u,e) = p; 162 // i + 2 ^ (e-1) ... i + 2 ^ e - 1
110 } 163 int i2 = rmq(i + (1 << (e-1)), e-1);
111 } 164 // choose index with minimum depth
112 }; 165 rmq(i,e) = D[i1] < D[i2] ? i1 : i2;
113 166 }
114 // ------------------------------------------ 167 }
115 // METHOD 2: SPARSE TABLE - EULER TOUR + RMQ 168 }
116 // ------------------------------------------ 169
117 // construction: O(2|V| log 2|V|) = O(|V| log |V|) 170 int lca(int u, int v) {
118 // query: O(1) (** assuming that __builtin_clz is mapped to an 171 // get ocurrence indexes in increasing order
119 // efficient processor instruction) 172 int l = H[u], r = H[v];
120 173 if (l > r) swap(l, r);
121 174 // get node with minimum depth in range [l .. r] in O(1)
122 struct LCA { 175 int len = r - l + 1;
123 vector<int> E, D, H; // E = euler tour, D = depth, H = first index of node in euler 176 int e = log2(len);
tour 177 int i1 = rmq(l,e);
124 vector<int> DP // memo for range minimun query 178 int i2 = rmq(r - ((1 << e) - 1), e);
125 vector<vector<int>> *g; // pointer to graph 179 return D[i1] < D[i2] ? E[i1] : E[i2];
126 int idx; // tracks node ocurrences 180 }
127 int n; // number of nodes 181
128 182 int dist(int u, int v) {
129 int& rmq(int i, int e) { return DP[e * idx + i]; } 183 // make sure you use H to retrieve the indexes of u and v
130 inline int log2(int x) { return 31 - __builtin_clz(x); } 184 // within the Euler Tour sequence before using D
131 185 return D[H[u]] + D[H[v]] - 2 * D[H[lca(u,v)]];
132 void dfs(int u, int depth) { 186 }
133 H[u] = idx; // index of first u’s ocurrence 187 }
134 E[idx] = u; // record node ocurrence 188
135 D[idx++] = depth; // record depth 189 // -----------------
136 for (int v : (*g)[u]) { 190 // EXAMPLE OF USAGE
137 if (H[v] == -1) { 191 // -----------------
138 dfs(v, depth + 1); // explore v’s subtree and come back to u 192 int main() {
139 E[idx] = u; // new ocurrence of u 193 // build graph
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.7 Diameter of a Tree Página 25 de 40
194 int n, m; 2 // Tarjan’s Algorithm
195 scanf("%d%d", &n, &m); 3 // -------------------
196 vector<vector<int>> g(n); 4 //references:
197 while (m--) { 5 //https://www.youtube.com/watch?v=jFZsDDB0-vo
198 int u, v; scanf("%d%d", &u, &v); 6 //https://www.hackerearth.com/practice/algorithms/graphs/articulation-points-and-bridges/
199 g[u].push_back(v); tutorial/
200 g[v].push_back(u); 7 //https://www.hackerearth.com/practice/algorithms/graphs/biconnected-components/tutorial/
201 } 8 //http://web.iitd.ac.in/~bspanda/biconnectedMTL776.pdf
202 // init LCA 9 typedef pair<int,int> ii;
203 LCA lca(g,0); 10 const int MAXN = 1000;
204 // answer queries 11 int depth[MAXN];
205 int q; scanf("%d", &q); 12 int low[MAXN];
206 while (q--) { 13 vector<int> g[MAXN];
207 int u, v; scanf("%d%d", &u, &v); 14 stack<ii> edge_stack;
208 printf("LCA(%d,%d) = %d\n", u, v, lca.lca(u,v)); 15
209 printf("dist(%d,%d) = %d\n", u, v, lca.dist(u,v)); 16 void print_and_remove_bicomp(int u, int v) {
210 } 17 puts("biconnected component found:");
211 }; 18 ii uv(u,v);
19 while (true) {
7.7 Diameter of a Tree 20 ii top = edge_stack.top();
21 edge_stack.pop();
1 // ========================== 22 printf("(%d, %d)\n", top.first, top.second);
2 // Find Tree’s Diameter Ends 23 if (top == uv) break;
3 // ========================== 24 }
4 const int MAXN = 10000; 25 }
5 26
6 int farthest_from(vector<vi>& g, int s) { // find farthest node from ’s’ with BFS 27 void dfs(int u, int p, int d) { // (node, parent, depth)
7 static int dist[MAXN]; 28 static num_root_children = 0;
8 memset(dist, -1, sizeof(int) * g.size()); 29 depth[u] = d;
9 int farthest = s; 30 low[u] = d; // u at least can reach itself (ignoring u-p edge)
10 queue<int> q; 31 for(int v : g[u]) {
11 q.push(s); 32 if (v == p) continue; // direct edge to parent -> ignore
12 dist[s] = 0; 33 if (depth[v] == -1) { // exploring a new, unvisited child node
13 while (!q.empty()) { 34 edge_stack.emplace(u,v); // add edge to stack
14 int u = q.front(); q.pop(); 35 dfs(v, u, d + 1); // explore recursively v’s subtree
15 for (int v : g[u]) { 36 // 1) detect articulation points and biconnected components
16 if (dist[v] == -1) { 37 if (p == -1) { // 1.1) special case: if u is root
17 dist[v] = dist[u] + 1; 38 if (++num_root_children == 2) {
18 q.push(v); 39 // we detected that root has AT LEAST 2 children
19 if (dist[v] > dist[farthest]) farthest = v; 40 // therefore root is an articulation point
20 } 41 printf("root = %d is articulation point\n", root);
21 } 42 }
22 } 43 // whenever we come back to the root, we just finished
23 return farthest; 44 // exploring a whole biconnected component
24 } 45 print_and_remove_bicomp(u,v);
25 46 } else if (low[v] >= d) { // 1.2) general case: non-root
26 void find_diameter(vector<vi>& g, int& e1, int& e2) { 47 printf("u = %d is articulation point\n", u);
27 e1 = farthest_from(g, 0); 48 // we entered through and came back to an AP,
28 e2 = farthest_from(g, e1); 49 // so we just finished exploring a whole biconnected component
29 } 50 print_and_remove_bicomp(u,v);
51 }
7.8 Articulation Points, Cut Edges, Biconnected Components 52 // 2) detect cut edges (a.k.a. bridges)
53 if (low[v] > depth[u]) {
1 // ------------------- 54 printf("(u,v) = (%d, %d) is cut edge\n", u, v);
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.9 Strongly Connected Components Página 26 de 40
55 } 40 ids.assign(n, -1);
56 // propagate low 41 low.resize(n);
57 low[u] = min(low[u], low[v]); 42 instack.assign(n, 0);
58 } else if (depth[v] < d) { // back-edge to proper ancestor 43 ID = 0;
59 edge_stack.emplace(u,v); // add edge to stack 44 rep(u, 0, n-1) if (ids[u] == -1) dfs(u);
60 low[u] = min(low[u], depth[v]); // propagate low 45 }
61 } else { // forward-edge to an already visited descendant 46 };
62 // => do nothing, because this edge was already considered as a 47
63 // back-edge from v -> u 48 // example of usage
64 } 49 int main() {
65 } 50 // read and build graph from standard input
66 } 51 int n, m; cin >> n >> m;
52 vector<vector<int>> g(n);
7.9 Strongly Connected Components 53 while(m--) {
54 int u, v; cin >> u >> v; u--, v--;
1 #include <bits/stdc++.h> 55 g[u].push_back(v);
2 #define rep(i,a,b) for(int i=a; i<=b; ++i) 56 }
3 using namespace std; 57 // find SCCs
4 // ----------------------------------------- 58 tarjanSCC tscc(g);
5 // implementation of Tarjan’s SCC algorithm 59 return 0;
6 struct tarjanSCC { 60 }
7 vector<int> _stack, ids, low;
8 vector<bool> instack; 7.10 Max Flow : Dinic
9 vector<vector<int>>* g;
10 int n, ID; 1 // Time Complexity:
11 void dfs(int u) { 2 // - general worst case: O (|E| * |V|^2)
12 ids[u] = low[u] = ID++; 3 // - unit capacities: O( min(V^(2/3), sqrt(E)) * E)
13 instack[u] = true; 4 // - Bipartite graph (unit capacities) + source & sink (any capacities): O(E sqrt V)
14 _stack.push_back(u); 5
15 for (int v : (*g)[u]) { 6 #include <bits/stdc++.h>
16 if (ids[v] == -1) { 7 using namespace std;
17 dfs(v); 8 typedef long long int ll;
18 low[u] = min(low[v], low[u]); 9
19 } else if (instack[v]) { 10 struct Dinic {
20 low[u] = min(low[v], low[u]); 11 struct edge {
21 } 12 int to, rev;
22 } 13 ll f, cap;
23 if (low[u] == ids[u]) { 14 };
24 // u is the root of a SCC 15
25 // ** here you can do whatever you want 16 vector<vector<edge>> g;
26 // with the SCC just found 17 vector<ll> dist;
27 cout << "SCC found!\n"; 18 vector<int> q, work;
28 // remove SCC from top of the stack 19 int n, sink;
29 while (1) { 20
30 int x = _stack.back(); _stack.pop_back(); 21 bool bfs(int start, int finish) {
31 instack[x] = false; 22 dist.assign(n, -1);
32 if (x == u) break; 23 dist[start] = 0;
33 } 24 int head = 0, tail = 0;
34 } 25 q[tail++] = start;
35 } 26 while (head < tail) {
36 tarjanSCC(vector<vector<int>>& _g) { 27 int u = q[head++];
37 g = &_g; 28 for (const edge &e : g[u]) {
38 n = _g.size(); 29 int v = e.to;
39 _stack.reserve(n); 30 if (dist[v] == -1 and e.f < e.cap) {
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - Página 27 de 40
31 dist[v] = dist[u] + 1; 84 int main() {
32 q[tail++] = v; 85 Dinic din(2);
33 } 86 din.add_edge(0,1,10);
34 } 87 ll mf = din.max_flow(0,1);
35 } 88 }
36 return dist[finish] != -1;
37
38
}
8 Mathematics
39 ll dfs(int u, ll f) {
40 if (u == sink) 8.1 Euclidean Algorithm
41 return f;
42 for (int &i = work[u]; i < (int)g[u].size(); ++i) { 1 typedef long long int ll;
43 edge &e = g[u][i]; 2
44 int v = e.to; 3 inline ll mod(ll x, ll m) { return ((x %= m) < 0) ? x+m : x; }
45 if (e.cap <= e.f or dist[v] != dist[u] + 1) 4
46 continue; 5 /* ============================= */
47 ll df = dfs(v, min(f, e.cap - e.f)); 6 /* GCD (greatest common divisor) */
48 if (df > 0) { 7 /* ============================= */
49 e.f += df; 8 // OPTION 1: using C++ builtin function __gcd
50 g[v][e.rev].f -= df; 9 __gcd(a,b)
51 return df; 10 // OPTION 2: manually usings euclid’s algorithm
52 } 11 int gcd (ll a, ll b) {
53 } 12 while (b) { a %= b; swap(a,b); }
54 return 0; 13 return a;
55 } 14 }
56 15
57 Dinic(int n) { 16 /* ============ */
58 this->n = n; 17 /* extended GCD */
59 g.resize(n); 18 /* ============ */
60 dist.resize(n); 19 // extended euclid’s algorithm: find g, x, y such that
61 q.resize(n); 20 // a * x + b * y = g = gcd(a, b)
62 } 21 // The algorithm finds a solution (x0,y0) but there are infinite more:
63 22 // x = x0 + n * (b/g)
64 void add_edge(int u, int v, ll cap) { 23 // y = y0 - n * (a/g)
65 edge a = {v, (int)g[v].size(), 0, cap}; 24 // where n is integer, are the set of all solutions
66 edge b = {u, (int)g[u].size(), 0, 0}; //Poner cap en vez de 0 si la arista es 25
bidireccional 26 // --- version 1: iterative
67 g[u].push_back(a); 27 ll gcdext(ll a, ll b, ll& x, ll& y) {
68 g[v].push_back(b); 28 ll r2, x2, y2, r1, x1, y1, r0, x0, y0, q;
69 } 29 r2 = a, x2 = 1, y2 = 0;
70 30 r1 = b, x1 = 0, y1 = 1;
71 ll max_flow(int source, int dest) { 31 while (r1) {
72 sink = dest; 32 q = r2 / r1;
73 ll ans = 0; 33 r0 = r2 % r1;
74 while (bfs(source, dest)) { 34 x0 = x2 - q * x1;
75 work.assign(n, 0); 35 y0 = y2 - q * y1;
76 while (ll delta = dfs(source, LLONG_MAX)) 36 r2 = r1, x2 = x1, y2 = y1;
77 ans += delta; 37 r1 = r0, x1 = x0, y1 = y0;
78 } 38 }
79 return ans; 39 ll g = r2; x = x2, y = y2;
80 } 40 if (g < 0) g = -g, x = -x, y = -y; // make sure g > 0
81 }; 41 // for debugging (in case you think you might have bugs)
82 42 // assert (g == a * x + b * y);
83 // usage 43 // assert (g == __gcd(abs(a),abs(b)));
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.2 Primality Test Página 28 de 40
44 return g; 97 /* Linear Congruence Equation */
45 } 98 /* ========================== */
46 99 // recommended reading:
47 // --- version 2: recursive 100 // http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/linear-congruences.
48 ll gcdext(ll a, ll b, ll& x, ll& y) { article.pdf
49 if (a == 0) { 101
50 x = 0, y = 1; 102 // find smallest integer x (mod m) that solves the equation
51 return b; 103 // a * x = b (mod m)
52 } 104 bool lincongeq(ll a, ll b, ll m, ll& x) {
53 ll x1, y1; 105 assert (m > 0);
54 ll g = gcdext(b % a, a, x1, y1); 106 a = mod(a,m);
55 x = y1 - (b / a) * x1; 107 b = mod(b,m);
56 y = x1; 108 ll s, t;
57 return g; 109 ll g = gcdext(a,m,s,t);
58 } 110 if (b % g == 0) {
59 111 ll bb = b/g;
60 /* ====================== */ 112 ll mm = m/g;
61 /* multiplicative inverse */ 113 ll n = -s*bb/mm;
62 /* ====================== */ 114 x = s*bb + n*mm;
63 // find x such that a * x = 1 (mod m) 115 if (x < 0) x += mm;
64 // this is the same as finding x, y such that 116 // for debugging
65 // a * x + m * y = 1, which can be done with gcdext 117 // assert (0 <= x and x < m);
66 // and then returning x (mod m) 118 // assert (mod(a*x,m) == b);
67 ll mulinv(ll a, ll m) { 119 return true;
68 ll x, y; 120 }
69 if (gcdext(a, m, x, y) == 1) return mod(x, m); // make sure 0 <= x < m 121 return false;
70 return -1; // no inverse exists 122 }
71 }
72 8.2 Primality Test
73 /* =========================== */
74 /* Linear Diophantine Equation */ 1 // ===============
75 /* =========================== */ 2 // trial division
76 // recommended readings: 3 //=================
77 // http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/linear-diophantine. 4 // complexity: ~O( sqrt(x) )
article.pdf 5 bool isPrime(int x) {
78 // http://mathonline.wikidot.com/solutions-to-linear-diophantine-equations 6 for (int d = 2; d * d <= x; d++) {
79 7 if (x % d == 0)
80 // find intengers x and y such that a * x + b * y = c 8 return false;
81 bool lindiopeq(ll a, ll b, ll c, ll& x, ll& y) { 9 }
82 if (a == 0 and b == 0) { // special case 10 return true;
83 if (c == 0) { x = y = 0; return true; } 11 }
84 return false; 12
85 } 13 // =======================================
86 // general case 14 // trial division with precomputed primes
87 ll s, t; 15 // =======================================
88 ll g = gcdext(a,b,s,t); 16 // complexity: ~O( sqrt(x)/log(sqrt(x)) )
89 if (c % g == 0) { 17 // + time of precomputing primes
90 x = s*(c/g), y = t*(c/g); 18 bool isPrime(int x, vector<int>& primes) {
91 return true; 19 for (int p : primes) {
92 } 20 if (p*p > x) break;
93 return false; 21 if (p % x == 0)
94 } 22 return false;
95 23 }
96 /* ========================== */ 24 return true;
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.3 Prime Factorization Página 29 de 40
25 } 79 }
26 80
27 81 bool MillerRabin(u64 n) { // returns true if n is prime, else returns false.
28 // ============= 82 if (n < 2)
29 // Miller-Rabin 83 return false;
30 // ============= 84
31 // complexity: O (k * log^3(n)) 85 int r = 0;
32 // references: 86 u64 d = n - 1;
33 // https://cp-algorithms.com/algebra/primality_tests.html 87 while ((d & 1) == 0) {
34 // https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Complexity 88 d >>= 1;
35 using u64 = uint64_t; 89 r++;
36 using u128 = __uint128_t; 90 }
37 91
38 u64 binpower(u64 base, u64 e, u64 mod) { 92 for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
39 u64 result = 1; 93 if (n == a)
40 base %= mod; 94 return true;
41 while (e) { 95 if (check_composite(n, a, d, r))
42 if (e & 1) 96 return false;
43 result = (u128)result * base % mod; 97 }
44 base = (u128)base * base % mod; 98 return true;
45 e >>= 1; 99 }
46 }
47 return result; 8.3 Prime Factorization
48 }
49 1 //=====================
50 bool check_composite(u64 n, u64 a, u64 d, int s) { 2 // Prime Factorization
51 u64 x = binpower(a, d, n); 3 //=====================
52 if (x == 1 || x == n - 1) 4 // reference: https://cp-algorithms.com/algebra/factorization.html
53 return false; 5
54 for (int r = 1; r < s; r++) { 6 // method 1: trial division
55 x = (u128)x * x % n; 7 // complexity: ~ O( sqrt(n) + log_2(n) )
56 if (x == n - 1) 8 vector<int> trial_division(int n) {
57 return false; 9 vector<int> factors;
58 } 10 for (int d = 2; d*d <= n; d++) {
59 return true; 11 while (n % d == 0) {
60 }; 12 factors.push_back(d);
61 13 if ((n /= d) == 1) return factors;
62 bool MillerRabin(u64 n) { // returns true if n is probably prime, else returns false. 14 }
63 if (n < 4) 15 }
64 return n == 2 || n == 3; 16 if (n > 1) factors.push_back(n);
65 17 return factors;
66 int s = 0; 18 }
67 u64 d = n - 1; 19
68 while ((d & 1) == 0) { 20 // method 2: precomputed primes
69 d >>= 1; 21 // complexity: ~ O( sqrt(n) / log(sqrt(n)) + log_2(n) )
70 s++; 22 // + time of precomputing primes
71 } 23 vector<int> trial_division_precomp(int n, vector<int>& primes) {
72 24 vector<int> factors;
73 for (int i = 0; i < iter; i++) { 25 for (int d : primes) {
74 int a = 2 + rand() % (n - 3); 26 if (d*d > n) break;
75 if (check_composite(n, a, d, s)) 27 while (n % d == 0) {
76 return false; 28 factors.push_back(d);
77 } 29 if ((n /= d) == 1) return factors;
78 return true; 30 }
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.4 Binary modular exponentiation Página 30 de 40
31 } 14 // choose(n,0) = choose(n,n) = 1
32 if (n > 1) factors.push_back(n); 15
33 return factors; 16 // 1.1) DP top-down
34 } 17 ll memo[MAXN+1][MAXN+1];
35 18 ll choose(int n, int k) {
36 //==================================== 19 ll& ans = memo[n][k];
37 // Prime Factorization of Factorials 20 if (ans != -1) return ans;
38 //==================================== 21 if (k == 0) return ans = 1;
39 // references: 22 if (n == k) return ans = 1;
40 // http://mathforum.org/library/drmath/view/67291.html 23 if (n < k) return ans = 0;
41 // https://janmr.com/blog/2010/10/prime-factors-of-factorial-numbers/ 24 return ans = (choose(n-1,k) + choose(n-1,k-1)) % MOD;
42 #define umap unordered_map 25 }
43 umap<int,int> factorial_prime_factorization(int n, vector<int>& primes) { 26
44 umap<int,int> prime2exp; 27 // 1.2) DP bottom-up
45 for (int p : primes) { 28 ll choose[MAXN+1][MAXN+1];
46 if (p > n) break; 29 rep(m,1,MAXN) {
47 int e = 0; 30 choose[m][0] = choose[m][m] = 1;
48 int tmp = n; 31 rep(k,1,m-1) choose[m][k] = (choose[m-1][k] + choose[m-1][k-1]) % MOD;
49 while ((tmp /= p) > 0) e += tmp; 32 }
50 if (e > 0) prime2exp[p] = e; 33
51 } 34 // -------------------------------------------------
52 return prime2exp; 35 // method 3: factorials and multiplicative inverse
53 } 36 // n! / (k! * (n-k)!) = n! * (k! * (n-k)!)^-1 (MOD N)
37 // we need to find the multiplicative inverse of (k! * (n-k)!) MOD N
8.4 Binary modular exponentiation 38
39 ll fac[MAXN+1];
40 ll choose_memo[MAXN+1][MAXN+1];
1 // compute a^b (mod m) 41 void init() {
2 int binary_exp(int a, int b, int m) { 42 fac[0] = 1;
3 a %= m; 43 rep(i,1,MAXN) fac[i] = (i * fac[i-1]) % MOD;
4 int res = 1; 44 memset(choose_memo, -1, sizeof choose_memo);
5 while (b > 0) { 45 }
6 if (b&1) res = (res * a) % m; 46 ll choose_mod(int n, int k) {
7 a = (a * a) % m; 47 if (choose_memo[n][k] != -1) return choose_memo[n][k];
8 b >>= 1; 48 return choose_memo[n][k] = mul(fac[n], mulinv(mul(fac[k], fac[n-k])));
9 } 49 }
10 return res;
11 } 8.6 Modular Multinomial Coefficient
8.5 Modular Binomial Coefficient 1 typedef long long int ll;
2 const ll MOD = 1000000007ll; // a prime number
1 #define rep(i,a,b) for(int i = a; i <= b; ++i) 3 const int MAXN = 1000;
2 typedef long long int ll; 4
3 const ll MOD = 1000000007ll; // a prime number 5 /* ===================== */
4 const int MAXN = 1000; 6 /* MODULAR MULTINOMIAL */
5 7 /* ===================== */
6 /* ================== */ 8
7 /* MODULAR BINOMIAL */ 9 ll memo[MAXN+1][MAXN+1];
8 /* ================== */ 10 ll choose(int n, int k) {
9 // choose_mod(n,k) = n! / (k! * (n-k)!) % MOD 11 ll& ans = memo[n][k];
10 12 if (ans != -1) return ans;
11 // --------------------- 13 if (k == 0) return ans = 1;
12 // method 1: DP 14 if (n == k) return ans = 1;
13 // choose(n,k) = (choose(n-1,k-1) + choose(n-1,k)) % MOD 15 if (n < k) return ans = 0;
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.7 Chinese Remainder Theorem (CRT) Página 31 de 40
16 return ans = (choose(n-1,k) + choose(n-1,k-1)) % MOD; 39 // sol = r1 + m1 * (r2-r1)/g * x’ (mod LCM(m1,m2))
17 } 40 // where x’ comes from
18 41 // m1 * x’ + m2 * y’ = g = GCD(m1,m2)
19 // reference: https://math.stackexchange.com/a/204209/503889 42 // where x’ and y’ are the values found by extended euclidean algorithm (gcdext)
20 ll multinomial(vector<int> ks) { 43 // Useful references:
21 int n = 0; 44 // https://codeforces.com/blog/entry/61290
22 ll ans = 1; 45 // https://forthright48.com/chinese-remainder-theorem-part-1-coprime-moduli
23 for (int k : ks) { 46 // https://forthright48.com/chinese-remainder-theorem-part-2-non-coprime-moduli
24 n += k; 47 // ** Note: this solution works if lcm(m1,m2) fits in a long long (64 bits)
25 ans = (ans * choose(n,k)) % MOD; 48 pair<ll,ll> CRT(ll r1, ll m1, ll r2, ll m2) {
26 } 49 ll g, x, y; g = gcdext(m1, m2, x, y);
27 return ans; 50 if ((r1 - r2) % g != 0) return {-1, -1}; // no solution
28 } 51 ll z = m2/g;
52 ll lcm = m1 * z;
8.7 Chinese Remainder Theorem (CRT) 53 ll sol = add(mod(r1, lcm), m1*mul(mod(x,z),mod((r2-r1)/g,z),z), lcm);
54 // for debugging (in case you think you might have bugs)
1 #include <bits/stdc++.h> 55 // assert (0 <= sol and sol < lcm);
2 typedef long long int ll; 56 // assert (sol % m1 == r1 % m1);
3 using namespace std; 57 // assert (sol % m2 == r2 % m2);
4 58 return {sol, lcm}; // solution + lcm(m1,m2)
5 inline ll mod(ll x, ll m) { return ((x %= m) < 0) ? x+m : x; } 59 }
6 inline ll mul(ll x, ll y, ll m) { return (x * y) % m; } 60
33 86 /* ========================= */
34 /* ========================================================= */ 87 /* Line Segment Intersection */
35 /* Cross Product -> orientation of point with respect to ray */ 88 /* ========================= */
36 /* ========================================================= */ 89 // returns whether segments p1q1 and p2q2 intersect, inspired by:
37 // cross product (b - a) x (c - a) 90 // https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
38 ll cross(Point& a, Point& b, Point& c) { 91 bool do_segments_intersect(Point& p1, Point& q1, Point& p2, Point& q2) {
39 ll dx0 = b.x - a.x, dy0 = b.y - a.y; 92 int o11 = orientation(p1, q1, p2);
40 ll dx1 = c.x - a.x, dy1 = c.y - a.y; 93 int o12 = orientation(p1, q1, q2);
41 return dx0 * dy1 - dx1 * dy0; 94 int o21 = orientation(p2, q2, p1);
42 // return (b - a).cross(c - a); // alternatively, using struct function 95 int o22 = orientation(p2, q2, q1);
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.2 Geometry 3D Utils Página 33 de 40
96 if (o11 != o12 and o21 != o22) // general case -> non-collinear intersection 150 }
97 return true; 151
98 if (o11 == o12 and o11 == 0) { // particular case -> segments are collinear 152 /* ==================================== */
99 Point dl1 = {min(p1.x, q1.x), min(p1.y, q1.y)}; 153 /* Point - Line / Line Segment distance */
100 Point ur1 = {max(p1.x, q1.x), max(p1.y, q1.y)}; 154 /* ==================================== */
101 Point dl2 = {min(p2.x, q2.x), min(p2.y, q2.y)}; 155 // reference: https://stackoverflow.com/questions/849211/shortest-distance-between-a-
102 Point ur2 = {max(p2.x, q2.x), max(p2.y, q2.y)}; point-and-a-line-segment
103 return do_rectangles_intersect(dl1, ur1, dl2, ur2); 156
104 } 157 // get distance between p and projection of p on line <- a - b ->
105 return false; 158 double point_line_dist(Point& p, Point& a, Point& b) {
106 } 159 Point d = b-a;
107 160 double t = d.dot(p-a) / d.norm2();
108 /* ======================== */ 161 return (a + d * t - p).norm();
109 /* Line - Line Intersection */ 162 }
110 /* ======================== */ 163
111 ll det(Point& a, Point& b) { return a.x * b.y - a.y * b.x; } 164 // get distance between p and truncated projection of p on segment a -> b
112 // return whether straight lines <-a1-b1-> and <-a2-b2-> intersect each other 165 double point_segment_dist(Point& p, Point& a, Point& b) {
113 // if they intersect, we assign values to t1 and t2 such that 166 if (a==b) return (p-a).norm(); // segment is a single point
114 // a1 + (b1 - a1) * t1 == a2 + (b2 - a2) * t2 167 Point d = b-a; // direction
115 bool find_line_line_intersection(Point& a1, Point& b1, Point& a2, Point& b2, 168 double t = d.dot(p-a) / d.norm2();
116 double& t1, double& t2) { 169 if (t <= 0) return (p-a).norm(); // truncate left
117 Point d1 = b1 - a1; 170 if (t >= 1) return (p-b).norm(); // truncate right
118 Point d2 = b2 - a2; 171 return (a + d * t - p).norm();
119 Point _d2 = d2 * -1; 172 }
120 ll detA = det(d1, _d2); 173
121 if (detA == 0) return false; // parallel lines 174 /* ====================================== */
122 Point b = a2 - a1; 175 /* Straight Line Hashing (integer coords) */
123 t1 = (double)det(b, _d2)/(double)detA; 176 /* ====================================== */
124 t2 = (double)det(d1, b)/(double)detA; 177 // task: given 2 points p1, p2 with integer coordinates, output a unique
125 return true; 178 // representation {a,b,c} such that a*x + b*y + c = 0 is the equation
126 } 179 // of the straight line defined by p1, p2. This representation must be
127 180 // unique for each straight line, no matter which p1 and p2 are sampled.
128 181 struct Point { ll x, y; };
129 /* =================== */ 182 tuple<ll,ll,ll> hash_line(const Point& p1, const Point& p2) {
130 /* Circle Intersection */ 183 ll a = p1.y - p2.y;
131 /* =================== */ 184 ll b = p2.x - p1.x;
132 struct Circle { double x, y, r; } 185 ll c = p1.x * (p2.y - p1.y) - p1.y * (p2.x - p1.x);
133 bool is_fully_outside(double r1, double r2, double d_sqr) { 186 ll sgn = (a < 0 or (a == 0 and b < 0)) ? -1 : 1;
134 double tmp = r1 + r2; 187 ll g = __gcd(abs(a), __gcd(abs(b), abs(c))) * sgn;
135 return d_sqr > tmp * tmp; 188 return make_tuple(a/g, b/g, c/g);
136 } 189 }
137 bool is_fully_inside(double r1, double r2, double d_sqr) { 190 // task: given 2 points p1 and p2 with integer coords, return a pair {a, b}
138 if (r1 > r2) return false; 191 // which is unique for all straight lines having the same slope as
139 double tmp = r2 - r1; 192 // the straight line that goes through p1 and p2
140 return d_sqr < tmp * tmp; 193 pair<ll,ll> hash_slope(const Point& p1, const Point& p2) {
141 } 194 ll dx = p2.x - p1.x;
142 bool do_circles_intersect(Circle& c1, Circle& c2) { 195 ll dy = p2.y - p1.y;
143 double dx = c1.x - c2.x; 196 ll sgn = (dx < 0 or (dx == 0 and dy < 0)) ? -1 : 1;
144 double dy = c1.y - c2.y; 197 ll g = __gcd(abs(dx), abs(dy)) * sgn;
145 double d_sqr = dx * dx + dy * dy; 198 return {dx/g, dy/g};
146 if (is_fully_inside(c1.r, c2.r, d_sqr)) return false; 199 }
147 if (is_fully_inside(c2.r, c1.r, d_sqr)) return false;
148 if (is_fully_outside(c1.r, c2.r, d_sqr)) return false; 9.2 Geometry 3D Utils
149 return true;
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.3 Polygon Algorithms Página 34 de 40
1 /* =========================== */ 9.3 Polygon Algorithms
2 /* Example of Point Definition */
3 /* =========================== */ 1 #include <bits/stdc++.h>
4 struct Point { // 3D 2 #define rep(i,a,b) for(int i = a; i <= b; ++i)
5 double x, y, z; 3
6 bool operator==(const Point& p) const { return x==p.x and y==p.y and z==p.z; } 4 // ----- Utils ------
7 Point operator+(const Point& p) const { return {x+p.x, y+p.y, z+p.z}; } 5 const double EPS = 1e-8;
8 Point operator-(const Point& p) const { return {x-p.x, y-p.y, z-p.z}; } 6 struct Point {
9 Point operator*(double d) const { return {x*d, y*d, z*d}; } 7 ll x, y;
10 double norm2() { return x*x + y*y + z*z; } 8 Point operator-(const Point& p) const { return {x - p.x, y - p.y}; }
11 double norm() { return sqrt(norm2()); } 9 Point operator+(const Point& p) const { return {x + p.x, y + p.y}; }
12 double dot(const Point& p) { return x*p.x + y*p.y + z*p.z; } 10 ll cross(const Point& p) const { return x*p.y - y*p.x; }
13 Point cross(Point& p) { 11 ll dot(const Point& p) const { return x*p.x + y*p.y; }
14 return { 12 };
15 y*p.z - z*p.y, 13 ll cross(Point& a, Point& b, Point& c) {
16 z*p.x - x*p.z, 14 ll dx0 = b.x - a.x, dy0 = b.y - a.y;
17 x*p.y - y*p.x 15 ll dx1 = c.x - a.x, dy1 = c.y - a.y;
18 }; 16 return dx0 * dy1 - dx1 * dy0;
19 } 17 }
20 Point unit() { 18 int orientation(Point& a, Point& b, Point& c) {
21 double d = norm(); 19 ll tmp = cross(a,b,c);
22 return {x/d, y/d, z/d}; 20 return tmp < 0 ? -1 : tmp == 0 ? 0 : 1; // sign
23 } 21 }
24 static Point from_sphere_coords(double r, double u, double v) { 22
25 return { 23 /* ======================================== */
26 r*cos(u)*cos(v), 24 /* Area of 2D non self intersecting Polygon */
27 r*cos(u)*sin(v), 25 /* ======================================== */
28 r*sin(u) 26 //based on Green’s Theorem:
29 }; 27 //http://math.blogoverflow.com/2014/06/04/greens-theorem-and-area-of-polygons/
30 } 28 // ** points must be sorted ccw or cw
31 }; 29 double polygon_area(vector<Point>& pol) {
32 // compute angle (0 <= angle <= PI) between vectors a and b 30 int n = pol.size()
33 // ** for better performance, the norms can be precomputed 31 double area = 0;
34 // or norms can be ommited altogether if a and b are unit vectors 32 for (int i = n-1, j = 0; j < n; i = j++) {
35 double angle_between(Point& a, Point& b) { 33 area += (pol[i].x + pol[j].x) * (pol[j].y - pol[i].y);
36 return acos(a.dot(b)/(a.norm() * b.norm())); 34 }
37 } 35 return area * 0.5; // use abs(area * 0.5) if points are cw
38 // check if point p belongs to the sphere arc from a to b. 36 }
39 // ** this assumes that a and b are points on a sphere centered at (0,0,0), 37
40 // and the sphere arc from a to b is the shortest path on the sphere connecting them 38 /* ================ */
41 const double EPS = 1e-8; 39 /* Point in Polygon */
42 bool point_in_arc(Point& a, Point& b, Point& p) { 40 /* ================ */
43 double angle_ab = angle_between(a, b); 41
44 double angle_ap = angle_between(a, p); 42 // -----------------------------
45 if (angle_ap > angle_ab) return false; 43 // 1) Convex Polygons
46 Point n = a.cross(b); 44
47 Point c_hat = n.cross(a).unit(); 45 // 1.1) O(N) method
48 double R = a.norm(); 46 bool point_in_convexhull(Point& p, vector<Point>& ch) {
49 Point a_hat = a * (1./R); 47 int n = ch.size();
50 Point a_rotated = (a_hat * cos(angle_ap) + c_hat * sin(angle_ap)) * R; 48 for (int i=n-1, j=0; j<n; i=j++) {
51 return (p - a_rotated).norm() < EPS; 49 if (cross(ch[i], ch[j], p) < 0) return false;
52 } 50 }
51 return true;
52 }
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.3 Polygon Algorithms Página 35 de 40
53 107 }
54 // 1.2) O(log N) method 108
55 bool point_in_triangle(Point& a, Point& b, Point& c, Point& x) { 109 /* ================================= */
56 return cross(a, b, x) >= 0 and cross(b, c, x) >= 0 and cross(c, a, x) >= 0; 110 /* Find extreme point in Convex Hull */
57 } 111 /* ================================= */
58 bool point_in_convexhull(Point& p, vector<Point>& ch) { 112 // given two points a and b defining a vector a -> b, and given a convex hull with points
59 if (cross(ch[0], ch[1], p) < 0) return false; 113 // sorted ccw, find the index in the convex hull of the extreme point.
60 if (cross(ch[0], ch.back(), p) > 0) return false; 114 // ** the extreme point is the "leftmost" point in the convex hull with respect to the
61 int l = 2, r = ch.size() - 1; 115 // vector a -> b (if there are 2 leftmost points, pick anyone)
62 while (l < r) { 116 int extreme_point_index(Point &a, Point &b, vector<Point> &ch) {
63 int m = (l+r) >> 1; 117 int n = ch.size();
64 if (cross(ch[0], ch[m], p) <= 0) r = m; 118 Point v = b - a;
65 else l = m+1; 119 v = Point(-v.y, v.x); // to find the leftmost point
66 } 120 if (v.dot(ch[0]) >= v.dot(ch[1]) && v.dot(ch[0]) >= v.dot(ch[n - 1])) {
67 return point_in_triangle(ch[0], ch[l-1], ch[l], p); 121 return 0;
68 } 122 }
69 123 int l = 0, r = n;
70 // ---------------------------------------------- 124 while (true) {
71 // 2) General methods: for complex / simple polygons 125 int m = (l + r) / 2;
72 126 if (v.dot(ch[m]) >= v.dot(ch[m + 1]) && v.dot(ch[m]) >= v.dot(ch[m - 1])) {
73 /* Nonzero Rule (winding number) */ 127 return m;
74 bool inPolygon_nonzero(Point p, vector<Point>& pts) { 128 }
75 int wn = 0; // winding number 129 int d1 = v.dot(ch[l + 1] - ch[l]) > 0;
76 Point prev = pts.back(); 130 int d2 = v.dot(ch[m + 1] - ch[m]) > 0;
77 rep (i, 0, (int)pts.size() - 1) { 131 int a = v.dot(ch[m]) > v.dot(ch[l]);
78 Point curr = pts[i]; 132 if (d1) { if (d2 && a) l = m; else r = m; }
79 if (prev.y <= p.y) { 133 else { if (!d2 && a) r = m; else l = m; }
80 if (p.y < curr.y && cross(prev, curr, p) > 0) 134 }
81 ++ wn; // upward & left 135 }
82 } else { 136
83 if (p.y >= curr.y && cross(prev, curr, p) < 0) 137 /* ========================================= */
84 -- wn; // downward & right 138 /* Line Segment and Convex Hull Intersection */
85 } 139 /* ========================================= */
86 prev = curr; 140 pair<int,int> find_crossing_edge(Point& a, Point& b, vector<Point>& ch, int start, int
87 } end) {
88 return wn != 0; // non-zero :) 141 int o_ref = orientation(a, b, ch[start]);
89 } 142 int n = ch.size();
90 143 int l = start, r = start + ((end - start + n) % n);
91 /* EvenOdd Rule (ray casting - crossing number) */ 144 while (l < r) {
92 bool inPolygon_evenodd(Point p, vector<Point>& pts) { 145 int m = (l+r) >> 1;
93 int cn = 0; // crossing number 146 if (orientation(a, b, ch[m % n]) != o_ref) r = m;
94 Point prev = pts.back(); 147 else l = m+1;
95 rep (i, 0, (int)pts.size() - 1) { 148 }
96 Point curr = pts[i]; 149 return {(l-1+n) % n, l%n};
97 if (((prev.y <= p.y) && (p.y < curr.y)) // upward crossing 150 }
98 || ((prev.y > p.y) && (p.y >= curr.y))) { // downward crossing 151 void find_segment_convexhull_intersection(Point& a, Point& b, vector<Point>& ch) {
99 // check intersect’s x-coordinate to the right of p 152 // find rightmost and leftmost points in convex hull wrt vector a -> b
100 double t = (p.y - prev.y) / (curr.y - prev.y); 153 int i1 = extreme_point_index(a, b, ch);
101 if (p.x < prev.x + t * (curr.x - prev.x)) 154 int i2 = extreme_point_index(b, a, ch);
102 ++cn; 155 // make sure the extremes are not to the same side
103 } 156 int o1 = orientation(a, b, ch[i1]);
104 prev = curr; 157 int o2 = orientation(a, b, ch[i2]);
105 } 158 if (o1 == o2) return; // all points are to the right (left) of a -> b (no
106 return (cn & 1); // odd -> in, even -> out intersection)
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.4 Trigonometry Página 36 de 40
159 // find 2 edges in the convex hull intersected by the straight line <- a - b -> 2 using namespace std;
160 pair<int,int> e1 = find_crossing_edge(a, b, ch, i1, i2); // binsearch from i1 to i2 3 #define rep(i,a,b) for(int i = a; i <= b; ++i)
ccw 4 #define invrep(i,b,a) for(int i = b; i >= a; --i)
161 pair<int,int> e2 = find_crossing_edge(a, b, ch, i2, i1); // binsearch from i2 to i1 5 typedef long long int ll;
ccw 6 // ----------------------------------------------
162 // find exact intersection points 7 // Convex Hull: Andrew’s Montone Chain Algorithm
163 double r1, s1, r2, s2; 8 // ----------------------------------------------
164 assert (find_line_line_intersection(a, b, ch[e1.first], ch[e1.second], r1, s1)); 9 struct Point {
165 assert (find_line_line_intersection(a, b, ch[e2.first], ch[e2.second], r2, s2)); 10 ll x, y;
166 // make sure intersections are significant and within line segment range 11 bool operator<(const Point& p) const {
167 if (r1 > 1.0 - EPS and r2 > 1.0 - EPS) return; // intersections above line segment 12 return x < p.x || (x == p.x && y < p.y);
168 if (r1 < EPS and r2 < EPS) return; // intersections below line segment 13 }
169 if (abs(r1 - r2) < EPS) return; // insignificant intersection in a single point 14 };
170 if (r1 > r2) swap(r1, r2), swap(e1, e2), swap(s1, s2); // make sure r1 < r2 15
171 // ** HERE DO WHATEVER YOU WANT WITH INTERSECTIONS FOUND 16 ll cross(Point& a, Point& b, Point& c) {
172 // 1) a + (b-a) * max(r1, 0) <--- first point of segment a -> b inside convex hull 17 ll dx0 = b.x - a.x, dy0 = b.y - a.y;
173 // if r1 < 0, point a is strictly inside the convex hull 18 ll dx1 = c.x - a.x, dy1 = c.y - a.y;
174 // 2) a + (b-a) * min(r2, 1) <--- last point of segment a -> b inside convex hull 19 return dx0 * dy1 - dx1 * dy0;
175 // if r2 > 1, point b is strictly inside the convex hull 20 }
176 cout << "(significant) intersection detected!\n"; 21
177 } 22 vector<Point> upper_hull(vector<Point>& P) {
23 // sort points lexicographically
9.4 Trigonometry 24 int n = P.size(), k = 0;
25 sort(P.begin(), P.end());
1 /* ================= */ 26 // build upper hull
2 /* Angle of a vector */ 27 vector<Point> uh(n);
3 /* ================= */ 28 invrep (i, n-1, 0) {
4 const double PI = acos(-1); 29 while (k >= 2 && cross(uh[k-2], uh[k-1], P[i]) <= 0) k--;
5 const double _2PI = 2 * PI; 30 uh[k++] = P[i];
6 31 }
7 double correct_angle(double angle) { // to ensure 0 <= angle <= 2PI 32 uh.resize(k);
8 while (angle < 0) angle += _2PI; 33 return uh;
9 while (angle > _2PI) angle -= _2PI; 34 }
10 return angle; 35
11 } 36 vector<Point> lower_hull(vector<Point>& P) {
12 double angle(double x, double y) { 37 // sort points lexicographically
13 // atan2 by itself returns an angle in range [-PI, PI] 38 int n = P.size(), k = 0;
14 // no need to "correct it" if that range is ok for you 39 sort(P.begin(), P.end());
15 return correct_angle(atan2(y, x)); 40 // collect lower hull
16 } 41 vector<Point> lh(n);
17 42 rep (i, 0, n-1) {
18 /* ============== */ 43 while (k >= 2 && cross(lh[k-2], lh[k-1], P[i]) <= 0) k--;
19 /* Cosine Theorem */ 44 lh[k++] = P[i];
20 /* ============== */ 45 }
21 // Given triangle with sides a, b and c, returns the angle opposed to side a. 46 lh.resize(k);
22 // a^2 = b^2 + c^2 - 2*b*c*cos(alpha) 47 return lh;
23 // => alpha = acos((b^2 + c^2 - a^2) /(2*b*c)) 48 }
24 double get_angle(double a, double b, double c) { 49