0% found this document useful (0 votes)
40 views23 pages

ACM-ICPC Reference Guide for Kardan University

The ACM-ICPC Team Reference Document from Kardan University provides a comprehensive guide on various programming concepts, algorithms, and data structures. It covers topics such as search algorithms, data structures like segment trees and graphs, mathematical concepts, and dynamic programming techniques. Additionally, it includes templates for C++ and Python, as well as practice solutions for competitive programming.

Uploaded by

elhamtesting1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
40 views23 pages

ACM-ICPC Reference Guide for Kardan University

The ACM-ICPC Team Reference Document from Kardan University provides a comprehensive guide on various programming concepts, algorithms, and data structures. It covers topics such as search algorithms, data structures like segment trees and graphs, mathematical concepts, and dynamic programming techniques. Additionally, it includes templates for C++ and Python, as well as practice solutions for competitive programming.

Uploaded by

elhamtesting1
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 1 of 23

ACM-ICPC Team Reference Document


Kardan University (Mohammad Masoom Wahid, Ahmad
Sohail Raoufi, Said Yousuf Said)
Contents 5 General 14
5.1 C++ Template . . . . . . . . . . . . . 14
1 Misc 2
1.1 Ternary Search . . . . . . . . . . . . . 2 5.2 Automatic Test . . . . . . . . . . . . . 15
1.2 Binary Exponentiation . . . . . . . . . 2 5.3 Python Template . . . . . . . . . . . . 15
1.3 Builtin GCC Stuff . . . . . . . . . . . 2 5.4 C++ Visual Studio Includes . . . . . . 15
1.4 Big Integer . . . . . . . . . . . . . . . 2
5.5 Compilation . . . . . . . . . . . . . . . 15
1.5 Mo’s Algorithm . . . . . . . . . . . . . 4

2 Data Structures 4 6 Math 15


2.1 Segment Tree . . . . . . . . . . . . . . 4 6.1 Formulas . . . . . . . . . . . . . . . . 15
2.2 Fenwick Tree Point Update And 6.2 Big Integer Multiplication With FFT . 15
Range Query . . . . . . . . . . . . . . 4
2.3 Fenwick Tree Range Update And 6.3 FFT . . . . . . . . . . . . . . . . . . . 16
Point Query . . . . . . . . . . . . . . . 4 6.4 Sprague Grundy Theorem . . . . . . . 16
2.4 Treap . . . . . . . . . . . . . . . . . . 5 6.5 Burnside’s Lemma . . . . . . . . . . . 16
2.5 Fenwick Tree Range Update And 6.6 Extended Euclidean Algorithm . . . . 17
Range Query . . . . . . . . . . . . . . 5
2.6 Disjoin Set Union . . . . . . . . . . . . 5 6.7 Chinese Remainder Theorem . . . . . 17
2.7 Fenwick 2D . . . . . . . . . . . . . . . 5 6.8 Gaussian Elimination . . . . . . . . . . 17
2.8 Segment Tree With Lazy Propagation 6 6.9 Linear Sieve . . . . . . . . . . . . . . . 17
2.9 Trie . . . . . . . . . . . . . . . . . . . 6 6.10 Simpson Integration . . . . . . . . . . 18
2.10 Implicit Treap . . . . . . . . . . . . . . 6
6.11 FFT With Modulo . . . . . . . . . . . 18
3 Geometry 7 6.12 Euler Totient Function . . . . . . . . . 18
3.1 2d Vector . . . . . . . . . . . . . . . . 7 6.13 Modular Inverse . . . . . . . . . . . . 18
3.2 Number Of Lattice Points On Segment 8
6.14 Factorization With Sieve . . . . . . . . 18
3.3 Common Tangents To Two Circles . . 8
3.4 Convex Hull With Graham’s Scan . . 8
3.5 Pick’s Theorem . . . . . . . . . . . . . 8 7 Pracitce Solutions 19
3.6 Misc . . . . . . . . . . . . . . . . . . . 8 7.1 H . . . . . . . . . . . . . . . . . . . . . 19
3.7 Circle Circle Intersection . . . . . . . . 9 7.2 F . . . . . . . . . . . . . . . . . . . . . 19
3.8 Circle Line Intersection . . . . . . . . 9
7.3 B . . . . . . . . . . . . . . . . . . . . . 20
3.9 Convex Hull Gift Wrapping . . . . . . 9
3.10 Usage Of Complex . . . . . . . . . . . 10
3.11 Line . . . . . . . . . . . . . . . . . . . 10 8 Dynamic Programming 20
8.1 Convex Hull Trick . . . . . . . . . . . 20
4 Graphs 10
8.2 Divide And Conquer . . . . . . . . . . 20
4.1 Number Of Paths Of Fixed Length . . 10
4.2 Max Flow With Dinic . . . . . . . . . 10 8.3 Optimizations . . . . . . . . . . . . . . 21
4.3 Max Flow With Dinic 2 . . . . . . . . 11
4.4 Min Cut . . . . . . . . . . . . . . . . . 11 9 Strings 21
4.5 Bellman Ford Algorithm . . . . . . . . 11 9.1 Prefix Function Automaton . . . . . . 21
4.6 Shortest Paths Of Fixed Length . . . . 11
9.2 KMP . . . . . . . . . . . . . . . . . . . 21
4.7 Bipartite Graph . . . . . . . . . . . . . 11
4.8 Finding Bridges . . . . . . . . . . . . . 12 9.3 Prefix Function . . . . . . . . . . . . . 21
4.9 Strongly Connected Components . . . 13 9.4 Prefix Sum Array 2d . . . . . . . . . . 21
4.10 Finding Articulation Points . . . . . . 13 9.5 Aho Corasick Automaton . . . . . . . 22
4.11 Dfs With Timestamps . . . . . . . . . 13
9.6 Suffix Array . . . . . . . . . . . . . . . 22
4.12 Max Flow With Ford Fulkerson . . . . 13
4.13 Lowest Common Ancestor . . . . . . . 14 9.7 Prefix Sum Array 1d . . . . . . . . . . 23
4.14 Dijkstra . . . . . . . . . . . . . . . . . 14 9.8 Hashing . . . . . . . . . . . . . . . . . 23
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 2 of 23

1 Misc string s;
ss >> s;
return s;
1.1 Ternary Search }
int sumof() {
string s = to_string();
double ternary_search(double l, double r) {
int ans = 0;
while (r - l > eps) {
for (auto c : s) ans += c - ’0’;
double m1 = l + (r - l) / 3;
return ans;
double m2 = r - (r - l) / 3;
}
double f1 = f(m1);
bigint() : sign(1) {}
double f2 = f(m2);
bigint(long long v) {
if (f1 < f2)
*this = v;
l = m1;
}
else
bigint(const string &s) {
r = m2;
read(s);
}
}
return f(l); //return the maximum of f(x) in [l, r]
void operator=(const bigint &v) {
}
sign = [Link];
a = v.a;
}
void operator=(long long v) {
1.2 Binary Exponentiation sign = 1;
[Link]();
ll pwr(ll a, ll b, ll m) { if (v < 0)
if(a == 1) return 1; sign = -1, v = -v;
if(b == 0) return 1; for (; v > 0; v = v / base)
a %= m; a.push_back(v % base);
ll res = 1; }
while (b > 0) { bigint operator+(const bigint &v) const {
if (b & 1) if (sign == [Link]) {
res = res * a % m; bigint res = v;
a = a * a % m; for (int i = 0, carry = 0; i < (int)max([Link](), v.a.
b >>= 1; size()) || carry; ++i) {
} if (i == (int)[Link]()) res.a.push_back(0);
return res; res.a[i] += carry + (i < (int)[Link]() ? a[i] : 0);
} carry = res.a[i] >= base;
if (carry) res.a[i] -= base;
}
return res;
}
1.3 Builtin GCC Stuff return *this - (-v);
}
• __builtin_clz(x): the number of zeros at the bigint operator-(const bigint &v) const {
if (sign == [Link]) {
beginning of the bit representation. if (abs() >= [Link]()) {
• __builtin_ctz(x): the number of zeros at the bigint res = *this;
for (int i = 0, carry = 0; i < (int)[Link]() ||
end of the bit representation. carry; ++i) {
• __builtin_popcount(x): the number of ones res.a[i] -= carry + (i < (int)[Link]() ? v.a[i] :
0);
in the bit representation. carry = res.a[i] < 0;
• __builtin_parity(x): the parity of the number if (carry) res.a[i] += base;
}
of ones in the bit representation. [Link]();
• __gcd(x, y): the greatest common divisor of return res;
}
two numbers. return -(v - *this);
• __int128_t: the 128-bit integer type. Does }
return *this + (-v);
not support input/output. }
void operator*=(int v) {
if (v < 0) sign = -sign, v = -v;
1.4 Big Integer for (int i = 0, carry = 0; i < (int)[Link]() || carry; ++i) {
if (i == (int)[Link]()) a.push_back(0);
long long cur = a[i] * (long long)v + carry;
const int base = 1000000000; carry = (int)(cur / base);
const int base_digits = 9; a[i] = (int)(cur % base);
struct bigint { }
vector<int> a; trim();
int sign; }
int size() { bigint operator*(int v) const {
if ([Link]()) return 0; bigint res = *this;
int ans = ([Link]() - 1) * base_digits; res *= v;
int ca = [Link](); return res;
while (ca) ans++, ca /= 10; }
return ans; void operator*=(long long v) {
} if (v < 0) sign = -sign, v = -v;
bigint operator^(const bigint &v) { for (int i = 0, carry = 0; i < (int)[Link]() || carry; ++i) {
bigint ans = 1, x = *this, y = v; if (i == (int)[Link]()) a.push_back(0);
while (![Link]()) { long long cur = a[i] * (long long)v + carry;
if (y % 2) ans *= x; carry = (int)(cur / base);
x *= x, y /= 2; a[i] = (int)(cur % base);
} }
return ans; trim();
} }
string to_string() { bigint operator*(long long v) const {
stringstream ss; bigint res = *this;
ss << *this;
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 3 of 23

res *= v; return *this < v || v < *this;


return res; }
} void trim() {
friend pair<bigint, bigint> divmod(const bigint &a1, const while (![Link]() && ![Link]()) a.pop_back();
bigint &b1) { if ([Link]()) sign = 1;
int norm = base / ([Link]() + 1); }
bigint a = [Link]() * norm; bool isZero() const {
bigint b = [Link]() * norm; return [Link]() || ([Link]() == 1 && !a[0]);
bigint q, r; }
[Link]([Link]()); bigint operator-() const {
for (int i = [Link]() - 1; i >= 0; i--) { bigint res = *this;
r *= base; [Link] = -sign;
r += a.a[i]; return res;
int s1 = [Link]() <= [Link]() ? 0 : r.a[[Link]()]; }
int s2 = [Link]() <= [Link]() - 1 ? 0 : r.a[[Link]() bigint abs() const {
- 1]; bigint res = *this;
int d = ((long long)base * s1 + s2) / [Link](); [Link] *= [Link];
r -= b * d; return res;
while (r < 0) r += b, --d; }
q.a[i] = d; long long longValue() const {
} long long res = 0;
[Link] = [Link] * [Link]; for (int i = [Link]() - 1; i >= 0; i--) res = res * base + a[i
[Link] = [Link]; ];
[Link](); return res * sign;
[Link](); }
return make_pair(q, r / norm); friend bigint gcd(const bigint &a, const bigint &b) {
} return [Link]() ? a : gcd(b, a % b);
bigint operator/(const bigint &v) const { }
return divmod(*this, v).first; friend bigint lcm(const bigint &a, const bigint &b) {
} return a / gcd(a, b) * b;
bigint operator%(const bigint &v) const { }
return divmod(*this, v).second; void read(const string &s) {
} sign = 1;
void operator/=(int v) { [Link]();
if (v < 0) sign = -sign, v = -v; int pos = 0;
for (int i = (int)[Link]() - 1, rem = 0; i >= 0; --i) { while (pos < (int)[Link]() && (s[pos] == ’-’ || s[pos] ==
long long cur = a[i] + rem * (long long)base; ’+’)) {
a[i] = (int)(cur / v); if (s[pos] == ’-’) sign = -sign;
rem = (int)(cur % v); ++pos;
} }
trim(); for (int i = [Link]() - 1; i >= pos; i -= base_digits) {
} int x = 0;
bigint operator/(int v) const { for (int j = max(pos, i - base_digits + 1); j <= i; j
bigint res = *this; ++)
res /= v; x = x * 10 + s[j] - ’0’;
return res; a.push_back(x);
} }
int operator%(int v) const { trim();
if (v < 0) v = -v; }
int m = 0; friend istream &operator>>(istream &stream, bigint &v) {
for (int i = [Link]() - 1; i >= 0; --i) string s;
m = (a[i] + m * (long long)base) % v; stream >> s;
return m * sign; [Link](s);
} return stream;
void operator+=(const bigint &v) { }
*this = *this + v; friend ostream &operator<<(ostream &stream, const bigint
} &v) {
void operator-=(const bigint &v) { if ([Link] == -1) stream << ’-’;
*this = *this - v; stream << ([Link]() ? 0 : [Link]());
} for (int i = (int)[Link]() - 2; i >= 0; --i)
void operator*=(const bigint &v) { stream << setw(base_digits) << setfill(’0’) << v.a[i
*this = *this * v; ];
} return stream;
void operator/=(const bigint &v) { }
*this = *this / v; static vector<int> convert_base(const vector<int> &a, int
} old_digits, int new_digits) {
bool operator<(const bigint &v) const { vector<long long> p(max(old_digits, new_digits) + 1);
if (sign != [Link]) return sign < [Link]; p[0] = 1;
if ([Link]() != [Link]()) for (int i = 1; i < (int)[Link](); i++)
return [Link]() * sign < [Link]() * [Link]; p[i] = p[i - 1] * 10;
for (int i = [Link]() - 1; i >= 0; i--) vector<int> res;
if (a[i] != v.a[i]) long long cur = 0;
return a[i] * sign < v.a[i] * sign; int cur_digits = 0;
return false; for (int i = 0; i < (int)[Link](); i++) {
} cur += a[i] * p[cur_digits];
bool operator>(const bigint &v) const { cur_digits += old_digits;
return v < *this; while (cur_digits >= new_digits) {
} res.push_back(int(cur % p[new_digits]));
bool operator<=(const bigint &v) const { cur /= p[new_digits];
return !(v < *this); cur_digits -= new_digits;
} }
bool operator>=(const bigint &v) const { }
return !(*this < v); res.push_back((int)cur);
} while (![Link]() && ![Link]()) res.pop_back();
bool operator==(const bigint &v) const { return res;
return !(*this < v) && !(v < *this); }
} typedef vector<long long> vll;
bool operator!=(const bigint &v) const { static vll karatsubaMultiply(const vll &a, const vll &b) {
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 4 of 23

int n = [Link](); 2 Data Structures


vll res(n + n);
if (n <= 32) {
for (int i = 0; i < n; i++) 2.1 Segment Tree
for (int j = 0; j < n; j++)
res[i + j] += a[i] * b[j];
return res; struct SegmentTree {
} int n;
int k = n >> 1; vector<ll> t;
vll a1([Link](), [Link]() + k); const ll IDENTITY = 0; // OO for min, -OO for max, ...
vll a2([Link]() + k, [Link]()); ll f(ll a, ll b) {
vll b1([Link](), [Link]() + k); return a+b;
vll b2([Link]() + k, [Link]()); }
SegmentTree(int _n) {
vll a1b1 = karatsubaMultiply(a1, b1); n = _n; t = vector<ll>(4*n, IDENTITY);
vll a2b2 = karatsubaMultiply(a2, b2); }
SegmentTree(vector<ll>& arr) {
for (int i = 0; i < k; i++) a2[i] += a1[i]; n = [Link](); t = vector<ll>(4*n, IDENTITY);
for (int i = 0; i < k; i++) b2[i] += b1[i]; build(arr, 1, 0, n-1);
}
vll r = karatsubaMultiply(a2, b2); void build(vector<ll>& arr, int v, int tl, int tr) {
for (int i = 0; i < (int)[Link](); i++) r[i] -= a1b1[i]; if(tl == tr) { t[v] = arr[tl]; }
for (int i = 0; i < (int)[Link](); i++) r[i] -= a2b2[i]; else {
int tm = (tl+tr)/2;
for (int i = 0; i < (int)[Link](); i++) res[i + k] += r[i]; build(arr, 2*v, tl, tm);
for (int i = 0; i < (int)[Link](); i++) res[i] += a1b1[i build(arr, 2*v+1, tm+1, tr);
]; t[v] = f(t[2*v], t[2*v+1]);
for (int i = 0; i < (int)[Link](); i++) res[i + n] += }
a2b2[i]; }
return res; // sum(1, 0, n-1, l, r)
} ll sum(int v, int tl, int tr, int l, int r) {
bigint operator*(const bigint &v) const { if(l > r) return IDENTITY;
vector<int> a6 = convert_base(this->a, base_digits, 6); if (l == tl && r == tr) return t[v];
vector<int> b6 = convert_base(v.a, base_digits, 6); int tm = (tl+tr)/2;
vll x([Link](), [Link]()); return f(sum(2*v, tl, tm, l, min(r, tm)), sum(2*v+1, tm
vll y([Link](), [Link]()); +1, tr, max(l, tm+1), r));
while ([Link]() < [Link]()) x.push_back(0); }
while ([Link]() < [Link]()) y.push_back(0); // update(1, 0, n-1, i, v)
while ([Link]() & ([Link]() - 1)) x.push_back(0), y. void update(int v, int tl, int tr, int pos, ll newVal) {
push_back(0); if(tl == tr) { t[v] = newVal; }
vll c = karatsubaMultiply(x, y); else {
bigint res; int tm = (tl+tr)/2;
[Link] = sign * [Link]; if(pos <= tm) update(2*v, tl, tm, pos, newVal);
for (int i = 0, carry = 0; i < (int)[Link](); i++) { else update(2*v+1, tm+1, tr, pos, newVal);
long long cur = c[i] + carry; t[v] = f(t[2*v],t[2*v+1]);
res.a.push_back((int)(cur % 1000000)); }
carry = (int)(cur / 1000000); }
} };
res.a = convert_base(res.a, 6, base_digits);
[Link]();
return res;
} 2.2 Fenwick Tree Point Update And
};
Range Query
struct Fenwick {
vector<ll> tree;
int n;
Fenwick(){}
Fenwick(int _n) {
n = _n;
1.5 Mo’s Algorithm tree = vector<ll>(n+1, 0);
}
void add(int i, ll val) { // arr[i] += val
Mo’s algorithm processes a set of range queries on for(; i <= n; i += i&(-i)) tree[i] += val;
}
a static array. Each query is to calculate something ll get(int i) { // arr[i]
base on the array values in a range [a, b]. The queries return sum(i, i);
}
have to be known in advance.√Let’s divide the ar- ll sum(int i) { // arr[1]+...+arr[i]
ray into blocks of size k = O( n). A query [a1 , b1 ] ll ans = 0;
for(; i > 0; i -= i&(-i)) ans += tree[i];
is processed before query [a2 , b2 ] if ⌊ ak1 ⌋ < ⌊ ak2 ⌋ or return ans;
⌊ ak1 ⌋ = ⌊ ak2 ⌋ and b1 < b2 . }
ll sum(int l, int r) {// arr[l]+...+arr[r]
return sum(r) - sum(l-1);
Example problem: counting number of distinct }
values in a range. We can process the queries in };
the described order and keep an array count, which
knows how many times a certain value has appeared.
When moving the boundaries back and forth, we ei- 2.3 Fenwick Tree Range Update And
ther increase count[xi ] or decrease it. According to Point Query
value of it, we will know how the number of distinct
struct Fenwick {
values has changed (e.g. if count[xi ] has just become vector<ll> tree;
1, then we add 1 to the answer, etc.). vector<ll> arr;
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 5 of 23

int n; recalc(tree);
Fenwick(vector<ll> _arr) { }
n = _arr.size();
arr = _arr; void erase(NodePtr tree, ll key) {
tree = vector<ll>(n+2, 0); if (!tree) return;
} if (tree->key == key) {
void add(int i, ll val) { // arr[i] += val merge(tree, tree->l, tree->r);
for(; i <= n; i += i&(-i)) tree[i] += val; }
} else {
void add(int l, int r, ll val) {// arr[l..r] += val erase(key < tree->key ? tree->l : tree->r, key);
add(l, val); }
add(r+1, -val); recalc(tree);
} }
ll get(int i) { // arr[i]
ll sum = arr[i-1]; // zero based void print(NodePtr t, bool newline = true) {
for(; i > 0; i -= i&(-i)) sum += tree[i]; if (!t) return;
return sum; // zero based print(t->l, false);
} cout << t->key << ”␣”;
}; print(t->r, false);
if (newline) cout << endl;
}
}
2.4 Treap
namespace Treap {
struct Node { 2.5 Fenwick Tree Range Update And
Node *l, *r;
ll key, prio, size; Range Query
Node() {}
Node(ll key) : key(key), l(nullptr), r(nullptr), size(1) {
prio = rand() ^ (rand() << 15); struct RangedFenwick {
} Fenwick F1, F2; // support range query and point update
}; RangedFenwick(int _n) {
F1 = Fenwick(_n+1);
typedef Node* NodePtr; F2 = Fenwick(_n+1);
}
int sz(NodePtr n) { void add(int l, int r, ll v) { // arr[l..r] += v
return n ? n->size : 0; [Link](l, v);
} [Link](r+1, -v);
[Link](l, v*(l-1));
void recalc(NodePtr n) { [Link](r+1, -v*r);
if (!n) return; }
n->size = sz(n->l) + 1 + sz(n->r); // add more ll sum(int i) { // arr[1..i]
operations here as needed return [Link](i)*[Link](i);
} }
ll sum(int l, int r) { // arr[l..r]
void split(NodePtr tree, ll key, NodePtr& l, NodePtr& r) { return sum(r)-sum(l-1);
if (!tree) { }
l = r = nullptr; };
}
else if (key < tree->key) {
split(tree->l, key, l, tree->l);

}
r = tree;
2.6 Disjoin Set Union
else {
split(tree->r, key, tree->r, r); struct DSU {
l = tree; vector<int> par;
} vector<int> sz;
recalc(tree);
} DSU(int n) {
FOR(i, 0, n) {
void merge(NodePtr& tree, NodePtr l, NodePtr r) { [Link](i);
if (!l || !r) { [Link](1);
tree = l ? l : r; }
} }
else if (l->prio > r->prio) {
merge(l->r, l->r, r); int find(int a) {
tree = l; return par[a] = par[a] == a ? a : find(par[a]);
} }
else {
merge(r->l, l, r->l); bool same(int a, int b) {
tree = r; return find(a) == find(b);
} }
recalc(tree);
} void unite(int a, int b) {
a = find(a);
void insert(NodePtr& tree, NodePtr node) { b = find(b);
if (!tree) { if(sz[a] > sz[b]) swap(a, b);
tree = node; sz[b] += sz[a];
} par[a] = b;
else if (node->prio > tree->prio) { }
split(tree, node->key, node->l, node->r); };
tree = node;
}
else {
insert(node->key < tree->key ? tree->l : tree->r,
node); 2.7 Fenwick 2D
}
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 6 of 23

struct Fenwick2D { lazy[v*2] = (lazy[v*2]*lazy[v])%MOD;


vector<vector<ll>> bit; t[v*2+1] = (t[v*2+1]*pwr(lazy[v], r-(mid+1)+1, MOD))
int n, m; %MOD;
Fenwick2D(int _n, int _m) { lazy[v*2+1] = (lazy[v*2+1]*lazy[v])%MOD;
n = _n; m = _m; lazy[v] = 1;
bit = vector<vector<ll>>(n+1, vector<ll>(m+1, 0)); }
} void update(int v, int tl, int tr, int l, int r, ll addend) {
ll sum(int x, int y) { if (l > r)
ll ret = 0; return;
for (int i = x; i > 0; i -= i & (-i)) if (l == tl && tr == r) {
for (int j = y; j > 0; j -= j & (-j)) t[v] = (t[v]*pwr(addend, tr-tl+1, MOD))%MOD;
ret += bit[i][j]; lazy[v] = (lazy[v]*addend)%MOD;
return ret; } else {
} push(v, tl, tr);
ll sum(int x1, int y1, int x2, int y2) { int tm = (tl + tr) / 2;
return sum(x2, y2) - sum(x2, y1-1) - sum(x1-1, y2) + update(v*2, tl, tm, l, min(r, tm), addend);
sum(x1-1, y1-1); update(v*2+1, tm+1, tr, max(l, tm+1), r, addend);
} t[v] = (t[v*2] * t[v*2+1]) % MOD;
void add(int x, int y, ll delta) { }
for (int i = x; i <= n; i += i & (-i)) }
for (int j = y; j <= m; j += j & (-j))
bit[i][j] += delta; ll query(int v, int tl, int tr, int l, int r) {
} if (l > r || r < tl || l > tr) return 1;
}; if (l <= tl && tr <= r) {
return t[v];
}
push(v, tl, tr);
2.8 Segment Tree With Lazy Propa- int tm = (tl + tr) / 2;
return (query(v*2, tl, tm, l, min(r, tm)) * query(v*2+1,
gation tm+1, tr, max(l, tm+1), r))%MOD;
}
};
// Add to segment, get maximum of segment
struct LazySegTree {
int n;
vector<ll> t, lazy;
LazySegTree(int _n) { 2.9 Trie
n = _n; t = vector<ll>(4*n, 0); lazy = vector<ll>(4*n,
0); struct Trie {
} const int ALPHA = 26;
LazySegTree(vector<ll>& arr) { const char BASE = ’a’;
n = _n; t = vector<ll>(4*n, 0); lazy = vector<ll>(4*n, vector<vector<int>> nextNode;
0); vector<int> mark;
build(arr, 1, 0, n-1); // same as in simple SegmentTree int nodeCount;
} Trie() {
void push(int v) { nextNode = vector<vector<int>>(MAXN, vector<int>(
t[v*2] += lazy[v]; ALPHA, -1));
lazy[v*2] += lazy[v]; mark = vector<int>(MAXN, -1);
t[v*2+1] += lazy[v]; nodeCount = 1;
lazy[v*2+1] += lazy[v]; }
lazy[v] = 0; void insert(const string& s, int id) {
} int curr = 0;
void update(int v, int tl, int tr, int l, int r, ll addend) { FOR(i, 0, (int)[Link]()) {
if (l > r) int c = s[i] - BASE;
return; if(nextNode[curr][c] == -1) {
if (l == tl && tr == r) { nextNode[curr][c] = nodeCount++;
t[v] += addend; }
lazy[v] += addend; curr = nextNode[curr][c];
} else { }
push(v); mark[curr] = id;
int tm = (tl + tr) / 2; }
update(v*2, tl, tm, l, min(r, tm), addend);
update(v*2+1, tm+1, tr, max(l, tm+1), r, addend); bool exists(const string& s) {
t[v] = max(t[v*2], t[v*2+1]); int curr = 0;
} FOR(i, 0, (int)[Link]()) {
} int c = s[i] - BASE;
if(nextNode[curr][c] == -1) return false;
int query(int v, int tl, int tr, int l, int r) { curr = nextNode[curr][c];
if (l > r || r < tl || l > tr) return -OO; }
if (l <= tl && tr <= r) return t[v]; return mark[curr] != -1;
push(v); }
int tm = (tl + tr) / 2; };
return max(query(v*2, tl, tm, l, r),
query(v*2+1, tm+1, tr, l, r));
}
}; 2.10 Implicit Treap
// Multiply every element on seg. by ‘addend‘, query product of
numbers in seg. template <typename T>
struct ProdTree { struct Node {
int n; Node* l, *r;
vector<ll> t, lazy; ll prio, size, sum;
ProdTree(int _n) { T val;
n = _n; t = vector<ll>(4*n, 1); lazy = vector<ll>(4*n, bool rev;
1); Node() {}
} Node(T _val) : l(nullptr), r(nullptr), val(_val), size(1), sum(
void push(int v, int l, int r) { _val), rev(false) {
int mid = (l+r)/2; prio = rand() ^ (rand() << 15);
t[v*2] = (t[v*2]*pwr(lazy[v], mid-l+1, MOD))%MOD; }
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 7 of 23

}; NodePtr fromArray(vector<T> v) {
template <typename T> NodePtr t = nullptr;
struct ImplicitTreap { FOR(i, 0, (int)[Link]()) {
typedef Node<T>* NodePtr; insert(t, v[i], i);
int sz(NodePtr n) { }
return n ? n->size : 0; return t;
} }
ll getSum(NodePtr n) {
return n ? n->sum : 0; ll calcSum(NodePtr t, int l, int r) {
} NodePtr L, R;
split(t, l, L, R);
void push(NodePtr n) { NodePtr good;
if (n && n->rev) { split(R, r - l + 1, good, L);
n->rev = false; return getSum(good);
swap(n->l, n->r); }
if (n->l) n->l->rev ^= 1; };
if (n->r) n->r->rev ^= 1; /* Usage: ImplicitTreap<int> t;
} Node<int> tree = [Link](someVector); [Link](tree, l, r);
} ...
*/
void recalc(NodePtr n) {
if (!n) return;
n->size = sz(n->l) + 1 + sz(n->r);
n->sum = getSum(n->l) + n->val + getSum(n->r);
}

void split(NodePtr tree, ll key, NodePtr& l, NodePtr& r) {


push(tree);
3 Geometry
if (!tree) {
l = r = nullptr;
} 3.1 2d Vector
else if (key <= sz(tree->l)) {
split(tree->l, key, l, tree->l);
r = tree;
} template <typename T>
else { struct Vec {
split(tree->r, key-sz(tree->l)-1, tree->r, r); T x, y;
l = tree; Vec(): x(0), y(0) {}
} Vec(T _x, T _y): x(_x), y(_y) {}
recalc(tree); Vec operator+(const Vec& b) {
} return Vec<T>(x+b.x, y+b.y);
}
void merge(NodePtr& tree, NodePtr l, NodePtr r) { Vec operator-(const Vec& b) {
push(l); push(r); return Vec<T>(x-b.x, y-b.y);
if (!l || !r) { }
tree = l ? l : r; Vec operator*(T c) {
} return Vec(x*c, y*c);
else if (l->prio > r->prio) { }
merge(l->r, l->r, r); T operator*(const Vec& b) {
tree = l; return x*b.x + y*b.y;
} }
else { T operator^(const Vec& b) {
merge(r->l, l, r->l); return x*b.y-y*b.x;
tree = r; }
} bool operator<(const Vec& other) const {
recalc(tree); if(x == other.x) return y < other.y;
} return x < other.x;
}
void insert(NodePtr& tree, T val, int pos) { bool operator==(const Vec& other) const {
if (!tree) { return x==other.x && y==other.y;
tree = new Node<T>(val); }
return; bool operator!=(const Vec& other) const {
} return !(*this == other);
NodePtr L, R; }
split(tree, pos, L, R); friend ostream& operator<<(ostream& out, const Vec& v) {
merge(L, L, new Node<T>(val)); return out << ”(” << v.x << ”,␣” << v.y << ”)”;
merge(tree, L, R); }
recalc(tree); friend istream& operator>>(istream& in, Vec<T>& v) {
} return in >> v.x >> v.y;
}
void reverse(NodePtr tree, int l, int r) { T norm() { // squared length
NodePtr t1, t2, t3; return (*this)*(*this);
split(tree, l, t1, t2); }
split(t2, r - l + 1, t2, t3); ld len() {
if(t2) t2->rev = true; return sqrt(norm());
merge(t2, t1, t2); }
merge(tree, t2, t3); ld angle(const Vec& other) { // angle between this and
} other vector
return acosl((*this)*other/len()/[Link]());
void print(NodePtr t, bool newline = true) { }
push(t); Vec perp() {
if (!t) return; return Vec(-y, x);
print(t->l, false); }
cout << t->val << ”␣”; };
print(t->r, false); /* Cross product of 3d vectors: (ay*bz-az*by, az*bx-ax*bz, ax*
if (newline) cout << endl; by-ay*bx)
} */
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 8 of 23

3.2 Number Of Lattice Points On [Link](a);


break;
Segment } else if((ba^ac) == 0) {
if(ba*ac < 0) c = a;
Let’s say we have a line segment from (x1 , y1 ) to // ^ c is between b and a, so it shouldn’t be
added to the hull
(x2 , y2 ). Then, the number of lattice points on this break;
segment is given by }
}
[Link](c);
gcd(x2 − x1 , y2 − y1 ) + 1. }
vector<Vec<int>> hullPts;
while(![Link]()) {
[Link]([Link]());
[Link]();
}
3.3 Common Tangents To Two Cir- }
return hullPts;

cles
struct pt {
double x, y; 3.5 Pick’s Theorem
pt operator- (pt p) { We are given a lattice polygon with non-zero area.
pt res = { x-p.x, y-p.y };
return res;
Let’s denote its area by S, the number of points with
} integer coordinates lying strictly inside the polygon
};
struct circle : pt {
by I and the number of points lying on the sides of
double r; the polygon by B. Then:
};
struct line {
B
};
double a, b, c; S=I+ − 1.
2
void tangents (pt c, double r1, double r2, vector<line> & ans) {
double r = r2 - r1;
double z = sqr(c.x) + sqr(c.y);
double d = z - sqr(r);
if (d < -eps) return;
d = sqrt (abs (d)); 3.6 Misc
line l;
l.a = (c.x * r + c.y * d) / z;
l.b = (c.y * r - c.x * d) / z;
l.c = r1; Distance from point to line.
ans.push_back (l);
} We have a line l(t) = ⃗a + ⃗bt and a point p⃗. The dis-
vector<line> tangents (circle a, circle b) {
vector<line> ans; tance from this point to the line can be calculated
for (int i=-1; i<=1; i+=2) by expressing the area of a triangle in two different
for (int j=-1; j<=1; j+=2)
p−⃗b)
tangents (b-a, a.r*i, b.r*j, ans); ways. The final formula: d = (⃗p−⃗a|⃗b−⃗
)×(⃗
a|
for (size_t i=0; i<[Link](); ++i)
ans[i].c -= ans[i].a * a.x + ans[i].b * a.y;
return ans;
} Point in polygon.
Send a ray (half-infinite line) from the points to an
arbitrary direction and calculate the number of times
3.4 Convex Hull With Graham’s Scan it touches the boundary of the polygon. If the num-
// Takes in >= 3 points
ber is odd, the point is inside the polygon, otherwise
// Returns convex hull in clockwise order it’s outside.
// Ignores points on the border
vector<Vec<int>> buildConvexHull(vector<Vec<int>> pts) {
if([Link]() <= 3) return pts; Using cross product to test rotation direction.
sort([Link](), [Link]());
stack<Vec<int>> hull;
[Link](pts[0]); Let’s say we have vectors ⃗a, ⃗b and ⃗c. Let’s define
auto p = pts[0]; ⃗ = b − a, bc
ab ⃗ = c − b and s = sgn(ab ⃗ × bc).
⃗ If s = 0,
sort([Link]()+1, [Link](), [&](Vec<int> a, Vec<int> b)
-> bool {
⃗ turns
the three points are collinear. If s = 1, then bc
// p->a->b is a ccw turn in the counterclockwise direction compared to the
int turn = sgn((a-p)^(b-a));
//if(turn == 0) return (a-p).norm() > (b-p).norm();
⃗ Otherwise it turns in the clockwise
direction of ab.
// ^ among collinear points, take the farthest one direction.
return turn == 1;
});
[Link](pts[1]);
FOR(i, 2, (int)[Link]()) { Line segment intersection.
auto c = pts[i];
if(c == [Link]()) continue; The problem: to check if line segments ab and cd
while(true) {
auto a = [Link](); [Link]();
intersect. There are three cases:
auto b = [Link](); 1. The line segments are on the same line.
auto ba = a-b;
auto ac = c-a;
Use cross products and check if they’re zero -
if((ba^ac) > 0) { this will tell if all points are on the same line.
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 9 of 23

If so, sort the points and check if their inter- 3. If point belongs to half-plane, add it to the an-
section is non-empty. If it is non-empty, there swer.
are an infinite number of intersection points. 4. If segment intersects the half-plane’s line, add
2. The line segments have a common ver- it to the answer.
tex. Four possibilities: a = c, a = d, b = c, b =
d. Some more techniques.
3. There is exactly one intersection point
that is not an endpoint. Use cross product • Check if point A lies on segment BC:
to check if points c and d are on different sides 1. Compute point-line distance and check if
of the line going through a and b and if the it is 0 (abs less than ϵ).
points a and b are on different sides of the line ⃗ BC
2. BA· ⃗ ≥ 0 and CA· ⃗ CB ⃗ ≥ 0.
going through c and d. • Compute distance between line segment and
point: project point onto line formed by the
Angle between vectors. segment. If this point is on the segment, then
the distance between it and original point is the

arccos( |⃗a⃗a|·|·b⃗b| ). answer. Otherwise, take minimum of distance
between point and segment endpoints.
Dot product properties.
If the dot product of two vectors is zero, the vectors
3.7 Circle Circle Intersection
are orthogonal. If it is positive, the angle is acute. Let’s say that the first circle is centered at (0, 0)
Otherwise it is obtuse. (if it’s not, we can move the origin to the center of
the first circle and adjust the coordinates), and the
Lines with line equation. second one is at (x2 , y2 ). Then, let’s construct a line
Ax + By + C = 0, where A = −2x2 , B = −2y2 , C =
Any line can be described by an equation ax + by + x22 + y22 + r12 − r22 . Finding the intersection between
c = 0. this line and the first circle will give us the answer.
• Construct a line using two points A and B: The only tricky case: if both circles are centered at
1. Take vector from A to B and rotate it 90 the same point. We handle this case separately.
degrees ((x, y) → (−y, x)). This will be
(a, b).
2. Normalize this vector. Then put A (or B) 3.8 Circle Line Intersection
into the equation and solve for c.
double r, a, b, c; // ax+by+c=0, radius is at (0, 0)
• Distance from point to line: put point coor- // If the center is not at (0, 0), fix the constant c to translate
dinates into line equation and take absolute everything so that center is at (0, 0)
double x0 = -a*c/(a*a+b*b), y0 = -b*c/(a*a+b*b);
value. If (a, b) √is not normalized, you still need if (c*c > r*r*(a*a+b*b)+eps)
to divide by a2 + b2 . puts (”no␣points”);
else if (abs (c*c - r*r*(a*a+b*b)) < eps) {
• Distance between two parallel lines: |c1 − c2 | puts (”1␣point”);
(if they are √ not normalized, you still need to cout << x0 << ’␣’ << y0 << ’\n’;
}
divide by a2 + b2 ). else {
• Project a point onto a line: compute signed dis- double d = r*r - c*c/(a*a+b*b);
double mult = sqrt (d / (a*a+b*b));
tance d between line L and point P . Answer double ax, ay, bx, by;
is P − d(a,⃗ b). ax = x0 + b * mult;
bx = x0 - b * mult;
• Build a line parallel to a given one and pass- ay = y0 - a * mult;
ing through a given point: compute the signed by = y0 + a * mult;
puts (”2␣points”);
distance d between line and point. Answer is cout << ax << ’␣’ << ay << ’\n’ << bx << ’␣’ << by
ax + by + (c − d) = 0. << ’\n’;
}
• Intersect two lines: d = a1 b2 − a2 b1 , x =
c2 b1 −c1 b2
d , y = c1 a2 −c
d
2 a1
. If abs(d) < ϵ, then
the lines are parallel.
3.9 Convex Hull Gift Wrapping
Half-planes. vector<Vec<int>> buildConvexHull(vector<Vec<int>>& pts)
{
Definition: define as line, assume a point (x, y) be- int n = [Link]();
sort([Link](), [Link]());
longs to half plane iff ax + by + c ≥ 0. auto currP = pts[0]; // choose some extreme point to be on
Intersecting with a convex polygon: the hull
1. Start at any point and move along the poly- vector<Vec<int>> hull;
gon’s traversal. set<Vec<int>> used;
[Link](pts[0]);
2. Alternate points and segments between consec- [Link](pts[0]);
utive points. while(true) {
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 10 of 23

auto candidate = pts[0]; // choose some point to be a gives the number of paths between i and j of length
candidate
k.
auto currDir = candidate-currP;
vector<Vec<int>> toUpdate;
FOR(i, 0, n) {
if(currP == pts[i]) continue;
// currently we have currP->candidate
// we need to find point to the left of this
4.2 Max Flow With Dinic
auto possibleNext = pts[i];
auto nextDir = possibleNext - currP;
auto cross = currDir ^ nextDir;
if(candidate == currP || cross > 0) { struct Edge {
candidate = possibleNext; int f, c;
currDir = nextDir; int to;
} else if(cross == 0 && [Link]() > currDir. pii revIdx;
norm()) { int dir;
candidate = possibleNext; int idx;
currDir = nextDir; };
}
} int n, m;
if([Link](candidate) != [Link]()) break; vector<Edge> adjList[MAX_N];
[Link](candidate); int level[MAX_N];
[Link](candidate);
currP = candidate; void addEdge(int a, int b, int c, int i, int dir) {
} int idx = adjList[a].size();
return hull; int revIdx = adjList[b].size();
} adjList[a].pb({ 0,c,b, {b, revIdx} ,dir,i });
adjList[b].pb({ 0,0,a, {a, idx} ,dir,i });
}

3.10 Usage Of Complex bool bfs(int s, int t) {


FOR(i, 0, n) level[i] = -1;
level[s] = 0;
typedef long long C; // could be long double queue<int> Q;
typedef complex<C> P; // represents a point or vector [Link](s);
#define X real() while (![Link]()) {
#define Y imag() auto t = [Link](); [Link]();
... for (auto x : adjList[t]) {
P p = {4, 2}; // p.X = 4, p.Y = 2 if (level[[Link]] < 0 && x.f < x.c) {
P u = {3, 1}; level[[Link]] = level[t] + 1;
P v = {2, 2}; [Link]([Link]);
P s = v+u; // {5, 3} }
P a = {4, 2}; }
P b = {3, -1}; }
auto l = abs(b-a); // 3.16228 return level[t] >= 0;
auto plr = polar(1.0, 0.5); // construct a vector of length 1 and }
angle 0.5 radians
v = {2, 2}; int send(int u, int f, int t, vector<int>& edgeIdx) {
auto alpha = arg(v); // 0.463648 if (u == t) return f;
v *= plr; // rotates v by 0.5 radians counterclockwise. The for (; edgeIdx[u] < adjList[u].size(); edgeIdx[u]++) {
length of plt must be 1 to rotate correctly. auto& e = adjList[u][edgeIdx[u]];
auto beta = arg(v); // 0.963648 if (level[[Link]] == level[u] + 1 && e.f < e.c) {
a = {4, 2}; int curr_flow = min(f, e.c - e.f);
b = {1, 2}; int next_flow = send([Link], curr_flow, t, edgeIdx);
C p = (conj(a)*b).Y; // 6 <- the cross product of a and b if (next_flow > 0) {
e.f += next_flow;
adjList[[Link]][[Link]].f -=
next_flow;
3.11 Line return next_flow;
}
template <typename T> }
struct Line { // expressed as two vectors }
Vec<T> start, dir; return 0;
Line() {} }
Line(Vec<T> a, Vec<T> b): start(a), dir(b-a) {}
int maxFlow(int s, int t) {
Vec<ld> intersect(Line l) { int f = 0;
ld t = ld(([Link]-start)^[Link])/(dir^[Link]); while (bfs(s, t)) {
// For segment-segment intersection this should be in vector<int> edgeIdx(n, 0);
range [0, 1] while (int extra = send(s, oo, t, edgeIdx)) {
Vec<ld> res(start.x, start.y); f += extra;
Vec<ld> dirld(dir.x, dir.y); }
return res + dirld*t; }
} return f;
}; }

void init() {
cin >> n >> m;
4 Graphs FOR(i, 0, m) {
int a, b, c;
cin >> a >> b >> c;
4.1 Number Of Paths Of Fixed a--; b--;
addEdge(a, b, c, i, 1);
Length addEdge(b, a, c, i, -1);
}
}
Let G be the adjacency matrix of a graph. Then
Ck = Gk gives a matrix, in which the value Ck [i][j]
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 11 of 23

4.3 Max Flow With Dinic 2 4.4 Min Cut


init();
struct FlowEdge { ll f = maxFlow(); // Ford-Fulkerson
int v, u; cur_time++;
long long cap, flow = 0; dfs(0);
FlowEdge(int v, int u, long long cap) : v(v), u(u), cap(cap) set<int> cc;
{} for (auto e : edges) {
}; if (timestamp[[Link]] == cur_time && timestamp[[Link]] !=
cur_time) {
struct Dinic { [Link]([Link]);
const long long flow_inf = 1e18; }
vector<FlowEdge> edges; }
vector<vector<int>> adj; // (# of edges in min-cut, capacity of cut)
int n, m = 0; // [indices of edges forming the cut]
int s, t; cout << [Link]() << ”␣” << f << endl;
vector<int> level, ptr; for (auto x : cc) cout << x + 1 << ”␣”;
queue<int> q;

Dinic(int n, int s, int t) : n(n), s(s), t(t) {


[Link](n);
[Link](n);
4.5 Bellman Ford Algorithm
[Link](n);
} struct Edge
{
void add_edge(int v, int u, long long cap) { int a, b, cost;
edges.push_back(FlowEdge(v, u, cap)); };
edges.push_back(FlowEdge(u, v, 0));
adj[v].push_back(m); int n, m, v; // v - starting vertex
adj[u].push_back(m + 1); vector<Edge> e;
m += 2;
} /* Finds SSSP with negative edge weights.
* Possible optimization: check if anything changed in a
bool bfs() { relaxation step. If not - you can break early.
while (![Link]()) { * To find a negative cycle: perform one more relaxation step. If
int v = [Link](); anything changes - a negative cycle exists.
[Link](); */
for (int id : adj[v]) { void solve() {
if (edges[id].cap - edges[id].flow < 1) vector<int> d (n, oo);
continue; d[v] = 0;
if (level[edges[id].u] != -1) for (int i=0; i<n-1; ++i)
continue; for (int j=0; j<m; ++j)
level[edges[id].u] = level[v] + 1; if (d[e[j].a] < oo)
[Link](edges[id].u); d[e[j].b] = min (d[e[j].b], d[e[j].a] + e[j].cost);
} // display d, for example, on the screen
} }
return level[t] != -1;
}

long long dfs(int v, long long pushed) { 4.6 Shortest Paths Of Fixed Length
if (pushed == 0)

return 0;
if (v == t)
Define A B = C ⇐⇒ Cij = minp=1..n (Aip +
return pushed; Bpj ). Let G be⊙ the adjacency
⊙ matrix of a graph.

for (int& cid = ptr[v]; cid < (int)adj[v].size(); cid++) {
int id = adj[v][cid];
Also, let Lk = G . . . G = G k . Then the value
int u = edges[id].u; Lk [i][j] denotes the length of the shortest path be-
if (level[v] + 1 != level[u] || edges[id].cap - edges[id].
flow < 1)
tween i and j which consists of exactly k edges.
continue;
long long tr = dfs(u, min(pushed, edges[id].cap -
edges[id].flow)); 4.7 Bipartite Graph
if (tr == 0)
continue; class BipartiteGraph {
edges[id].flow += tr; private:
edges[id ^ 1].flow -= tr; vector<int> _left, _right;
return tr; vector<vector<int>> _adjList;
} vector<int> _matchR, _matchL;
return 0; vector<bool> _used;
}
bool _kuhn(int v) {
long long flow() { if (_used[v]) return false;
long long f = 0; _used[v] = true;
while (true) { FOR(i, 0, (int)_adjList[v].size()) {
fill([Link](), [Link](), -1); int to = _adjList[v][i] - _left.size();
level[s] = 0; if (_matchR[to] == -1 || _kuhn(_matchR[to])) {
[Link](s); _matchR[to] = v;
if (!bfs()) _matchL[v] = to;
break; return true;
fill([Link](), [Link](), 0); }
while (long long pushed = dfs(s, flow_inf)) { }
f += pushed; return false;
} }
} void _addReverseEdges() {
return f; FOR(i, 0, (int)_right.size()) {
} if (_matchR[i] != -1) {
}; _adjList[_left.size() + i].pb(_matchR[i]);
}
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 12 of 23

}
} // Minimum Vertex Cover
void _dfs(int p) { // Algo: Find MM. Run DFS from unmatched vertices from
if (_used[p]) return; the left part.
_used[p] = true; // MVC is composed of unvisited LEFT and visited RIGHT
for (auto x : _adjList[p]) { vertices.
_dfs(x); pair<vector<int>, vector<int>> mvc(bool runMM = true)
} {
} if (runMM) mm();
vector<pii> _buildMM() { _addReverseEdges();
vector<pair<int, int> > res; fill(_used.begin(), _used.end(), false);
FOR(i, 0, (int)_right.size()) { FOR(i, 0, (int)_left.size()) {
if (_matchR[i] != -1) { if (_matchL[i] == -1) {
res.push_back(make_pair(_matchR[i], i)); _dfs(i);
} }
} }
vector<int> left, right;
return res; FOR(i, 0, (int)_left.size()) {
} if (!_used[i]) [Link](i);
public: }
void addLeft(int x) { FOR(i, 0, (int)_right.size()) {
_left.pb(x); if (_used[i + (int)_left.size()]) [Link](i);
_adjList.pb({}); }
_matchL.pb(-1); return { left,right };
_used.pb(false); }
}
void addRight(int x) { // Maximal Independant Vertex Set
_right.pb(x); // Algo: Find complement of MVC.
_adjList.pb({}); pair<vector<int>, vector<int>> mivs(bool runMM = true)
_matchR.pb(-1); {
_used.pb(false); auto m = mvc(runMM);
} vector<bool> containsL(_left.size(), false), containsR(
void addForwardEdge(int l, int r) { _right.size(), false);
_adjList[l].pb(r + _left.size()); for (auto x : [Link]) containsL[x] = true;
} for (auto x : [Link]) containsR[x] = true;
void addMatchEdge(int l, int r) { vector<int> left, right;
if(l != -1) _matchL[l] = r; FOR(i, 0, (int)_left.size()) {
if(r != -1) _matchR[r] = l; if (!containsL[i]) [Link](i);
} }
// Maximum Matching FOR(i, 0, (int)_right.size()) {
vector<pii> mm() { if (!containsR[i]) [Link](i);
_matchR = vector<int>(_right.size(), -1); }
_matchL = vector<int>(_left.size(), -1); return { left, right };
// ^ these two can be deleted if performing MM on }
already partially matched graph
_used = vector<bool>(_left.size() + _right.size(), false };
);

bool path_found; 4.8 Finding Bridges


do {
fill(_used.begin(), _used.end(), false);
path_found = false; int n; // number of nodes
FOR(i, 0, (int)_left.size()) { vector<vector<int>> adj; // adjacency list of graph
if (_matchL[i] < 0 && !_used[i]) {
path_found |= _kuhn(i); vector<bool> visited;
} vector<int> tin, fup;
} int timer;
} while (path_found);
void processBridge(int u, int v) {
return _buildMM(); // do something with the found bridge
} }

// Minimum Edge Cover void dfs(int v, int p = -1) {


// Algo: Find MM, add unmatched vertices greedily. visited[v] = true;
vector<pii> mec() { tin[v] = fup[v] = timer++;
auto ans = mm(); for (int to : adj[v]) {
FOR(i, 0, (int)_left.size()) { if (to == p) continue;
if (_matchL[i] != -1) { if (visited[to]) {
for (auto x : _adjList[i]) { fup[v] = min(fup[v], tin[to]);
int ridx = x - _left.size(); } else {
if (_matchR[ridx] == -1) { dfs(to, v);
[Link]({ i, ridx }); fup[v] = min(fup[v], fup[to]);
_matchR[ridx] = i; if (fup[to] > tin[v])
} processBridge(v, to);
} }
} }
} }
FOR(i, 0, (int)_left.size()) {
if (_matchL[i] == -1 && (int)_adjList[i].size() > 0) // Doesn’t work with multiple edges
{ // But multiple edges are never bridges, so it’s easy to check
int ridx = _adjList[i][0] - _left.size(); void findBridges() {
_matchL[i] = ridx; timer = 0;
[Link]({ i, ridx }); [Link](n, false);
} [Link](n, -1);
} [Link](n, -1);
return ans; [Link]();
} FOR(i, 0, n) {
if (!visited[i])
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 13 of 23

dfs(i); processCutpoint(v);
} }
}
void findCutpoints() {
timer = 0;
[Link](n, false);
4.9 Strongly Connected Components [Link](n, -1);
[Link](n, -1);
for (int i = 0; i < n; ++i) {
vector < vector<int> > g, gr; // adjList and reversed adjList if (!visited[i])
vector<bool> used; dfs (i);
vector<int> order, component; }
}
void dfs1 (int v) {
used[v] = true;
for (size_t i=0; i<g[v].size(); ++i)
if (!used[ g[v][i] ])
dfs1 (g[v][i]);
4.11 Dfs With Timestamps
order.push_back (v);
} vector<vector<int>> adj;
vector<int> tIn, tOut, color;
void dfs2 (int v) { int dfs_timer = 0;
used[v] = true;
component.push_back (v); void dfs(int v) {
for (size_t i=0; i<gr[v].size(); ++i) tIn[v] = dfs_timer++;
if (!used[ gr[v][i] ]) color[v] = 1;
dfs2 (gr[v][i]); for (int u : adj[v])
} if (color[u] == 0)
dfs(u);
int main() { color[v] = 2;
int n; tOut[v] = dfs_timer++;
// read n }
for (;;) {
int a, b;
// read edge a -> b
g[a].push_back (b);
gr[b].push_back (a);
4.12 Max Flow With Ford Fulkerson
}
struct Edge {
[Link] (n, false); int to, next;
for (int i=0; i<n; ++i) ll f, c;
if (!used[i]) int idx, dir;
dfs1 (i); int from;
[Link] (n, false); };
for (int i=0; i<n; ++i) {
int v = order[n-1-i]; int n, m;
if (!used[v]) { vector<Edge> edges;
dfs2 (v); vector<int> first;
// do something with the found component
[Link](); // components are generated in void addEdge(int a, int b, ll c, int i, int dir) {
toposort-order [Link]({ b, first[a], 0, c, i, dir, a });
} [Link]({ a, first[b], 0, 0, i, dir, b });
} first[a] = [Link]() - 2;
} first[b] = [Link]() - 1;
}

void init() {
4.10 Finding Articulation Points cin >> n >> m;
[Link](4 * m);
first = vector<int>(n, -1);
int n; // number of nodes FOR(i, 0, m) {
vector<vector<int>> adj; // adjacency list of graph int a, b, c;
cin >> a >> b >> c;
vector<bool> visited; a--; b--;
vector<int> tin, fup; addEdge(a, b, c, i, 1);
int timer; addEdge(b, a, c, i, -1);
}
void processCutpoint(int v) { }
// problem-specific logic goes here
// it can be called multiple times for the same v int cur_time = 0;
} vector<int> timestamp;

void dfs(int v, int p = -1) { ll dfs(int v, ll flow = OO) {


visited[v] = true; if (v == n - 1) return flow;
tin[v] = fup[v] = timer++; timestamp[v] = cur_time;
int children=0; for (int e = first[v]; e != -1; e = edges[e].next) {
for (int to : adj[v]) { if (edges[e].f < edges[e].c && timestamp[edges[e].to] !=
if (to == p) continue; cur_time) {
if (visited[to]) { int pushed = dfs(edges[e].to, min(flow, edges[e].c -
fup[v] = min(fup[v], tin[to]); edges[e].f));
} else { if (pushed > 0) {
dfs(to, v); edges[e].f += pushed;
fup[v] = min(fup[v], fup[to]); edges[e ^ 1].f -= pushed;
if (fup[to] >= tin[v] && p!=-1) return pushed;
processCutpoint(v); }
++children; }
} }
} return 0;
if(p == -1 && children > 1) }
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 14 of 23

while (![Link]()) {
ll maxFlow() { int v = [Link]().second;
cur_time = 0; int d_v = [Link]().first;
timestamp = vector<int>(n, 0); [Link]();
ll f = 0, add; if (d_v != d[v]) continue;
while (true) { for (auto edge : adj[v]) {
cur_time++; int to = [Link];
add = dfs(0); int len = [Link];
if (add > 0) { if (d[v] + len < d[to]) {
f += add; d[to] = d[v] + len;
} p[to] = v;
else { [Link]({d[to], to});
break; }
} }
} }
return f; }
}

4.13 Lowest Common Ancestor 5 General


int n, l; // l == logN (usually about ~20) 5.1 C++ Template
vector<vector<int>> adj;

int timer; #include <bits/stdc++.h>


vector<int> tin, tout; #include <ext/pb_ds/assoc_container.hpp> // gp_hash_table
vector<vector<int>> up; <int, int> == hash map
#include <ext/pb_ds/tree_policy.hpp>
void dfs(int v, int p) using namespace std;
{ using namespace __gnu_pbds;
tin[v] = ++timer; typedef long long ll;
up[v][0] = p; typedef unsigned long long ull;
// wUp[v][0] = weight[v][u]; // <- path weight sum to 2^i-th typedef long double ld;
ancestor typedef pair<int, int> pii;
for (int i = 1; i <= l; ++i) typedef pair<ll, ll> pll;
up[v][i] = up[up[v][i-1]][i-1]; typedef pair<double, double> pdd;
// wUp[v][i] = wUp[v][i-1] + wUp[up[v][i-1]][i-1]; template <typename T> using min_heap = priority_queue<T,
vector<T>, greater<T>>;
for (int u : adj[v]) { template <typename T> using max_heap = priority_queue<T,
if (u != p) vector<T>, less<T>>;
dfs(u, v); template <typename T> using ordered_set = tree<T,
} null_type, less<T>, rb_tree_tag,
tree_order_statistics_node_update>;
tout[v] = ++timer; template <typename K, typename V> using hashmap =
} gp_hash_table<K, V>;

bool isAncestor(int u, int v) template<typename A, typename B> ostream& operator<<(


{ ostream& out, pair<A, B> p) { out << ”(” << [Link]
return tin[u] <= tin[v] && tout[v] <= tout[u]; << ”,␣” << [Link] << ”)”; return out;}
} template<typename T> ostream& operator<<(ostream& out,
vector<T> v) { out << ”[”; for(auto& x : v) out << x
int lca(int u, int v) << ”,␣”; out << ”]”;return out;}
{ template<typename T> ostream& operator<<(ostream& out,
if (isAncestor(u, v)) set<T> v) { out << ”{”; for(auto& x : v) out << x <<
return u; ”,␣”; out << ”}”; return out; }
if (isAncestor(v, u)) template<typename K, typename V> ostream& operator<<(
return v; ostream& out, map<K, V> m) { out << ”{”; for(auto& e
for (int i = l; i >= 0; --i) { : m) out << [Link] << ”␣->␣” << [Link] << ”,␣”; out
if (!isAncestor(up[u][i], v)) << ”}”; return out; }
u = up[u][i]; template<typename K, typename V> ostream& operator<<(
} ostream& out, hashmap<K, V> m) { out << ”{”; for(
return up[u][0]; auto& e : m) out << [Link] << ”␣->␣” << [Link] <<
} ”,␣”; out << ”}”; return out; }

void preprocess(int root) { #define FAST_IO ios_base::sync_with_stdio(false); [Link](


[Link](n); NULL)
[Link](n); #define TESTS(t) int NUMBER_OF_TESTS; cin >>
timer = 0; NUMBER_OF_TESTS; for(int t = 1; t <=
l = ceil(log2(n)); NUMBER_OF_TESTS; t++)
[Link](n, vector<int>(l + 1)); #define FOR(i, begin, end) for (int i = (begin) - ((begin) > (
dfs(root, root); end)); i != (end) - ((begin) > (end)); i += 1 - 2 * ((begin)
} > (end)))
#define sgn(a) ((a) > eps ? 1 : ((a) < -eps ? -1 : 0))
#define precise(x) fixed << setprecision(x)
#define debug(x) cerr << ”>␣” << #x << ”␣=␣” << x <<
4.14 Dijkstra endl;
#define pb push_back
#define rnd(a, b) (uniform_int_distribution<int>((a), (b))(rng
vector<vector<pair<int, int>>> adj; ))
void dijkstra(int s, vector<int> & d, vector<int> & p) { #ifndef LOCAL
int n = [Link](); #define cerr if(0)cout
[Link](n, oo); #define endl ”\n”
[Link](n, -1); #endif
mt19937 rng(chrono::steady_clock::now().time_since_epoch().
d[s] = 0; count());
min_heap<pii> q; clock_t __clock__;
[Link]({0, s}); void startTime() {__clock__ = clock();}
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 15 of 23

void timeit(string msg) {cerr << ”>␣” << msg << ”:␣” << #include <unordered_map>
precise(6) << ld(clock()-__clock__)/ #include <unordered_set>
CLOCKS_PER_SEC << endl;} #include <complex>
const ld PI = asin(1) * 2; #include <random>
const ld eps = 1e-14; #include <chrono>
const int oo = 2e9;
const ll OO = 2e18;
const ll MOD = 1000000007;
const int MAXN = 1000000; 5.5 Compilation
int main() {
FAST_IO; # Simple compile
startTime(); g++ -DLOCAL -O2 -o [Link] -std-c++17 -Wall -Wno-unused
-result -Wshadow [Link]
timeit(”Finished”); # Debug
return 0; g++ -DLOCAL -std=c++17 -Wshadow -Wall -o [Link] main.
} cpp -fsanitize=address -fsanitize=undefined -fuse-ld=gold
-D_GLIBCXX_DEBUG -g

5.2 Automatic Test


6 Math
# Linux Bash
# gen, main and stupid have to be compiled beforehand
for((i=1;;++i)); do 6.1 Formulas
echo $i;
∑n ∑n 2
./gen $i > genIn;
i=1 i = n(n+1) ; i=1 i = n(2n+1)(n+1) ;
done
diff <(./main < genIn) <(./stupid < genIn) || break; ∑n 3 n2 (n+1)2 ∑n
2
4
6
n(n+1)(2n+1)(3n2 +3n−1)
i = ; i = ;
∑bi=1 i 4
cb+1 −ca
i=1
∑n 30
# Windows CMD
i=a c = c−1 , c ̸= 1; i=1 a1 + (i −
n(a1 +an ) ∑n
@echo off
a1 (1−r n )
FOR /L %%I IN (1,1,2147483647) DO ( 1)d = ; i=1 a1 r
i−1
= , r ̸= 1;
echo %%I ∑∞ 2 1−r
[Link] %%I > genIn i=1 ar i−1
= a1
1−r , |r| ≤ 1.
[Link] < genIn > mainOut
[Link] < genIn > stupidOut

)
FC mainOut stupidOut || goto :eof 6.2 Big Integer Multiplication With
FFT
complex<ld> a[MAX_N], b[MAX_N];
5.3 Python Template complex<ld> fa[MAX_N], fb[MAX_N], fc[MAX_N];
complex<ld> cc[MAX_N];
import sys
import re string mul(string as, string bs) {
from math import ceil, log, sqrt, floor int sgn1 = 1;
int sgn2 = 1;
__local_run__ = False if (as[0] == ’-’) {
if __local_run__: sgn1 = -1;
[Link] = open(’[Link]’, ’r’) as = [Link](1);
[Link] = open(’[Link]’, ’w’) }
if (bs[0] == ’-’) {
def main(): sgn2 = -1;
a = int(input()) bs = [Link](1);
b = int(input()) }
print(a*b) int n = [Link]() + [Link]() + 1;
FFT::init(n);
main() FOR(i, 0, FFT::pwrN) {
a[i] = b[i] = fa[i] = fb[i] = fc[i] = cc[i] = 0;
}
FOR(i, 0, [Link]()) {
5.4 C++ Visual Studio Includes }
a[i] = as[[Link]() - 1 - i] - ’0’;

FOR(i, 0, [Link]()) {
#define _CRT_SECURE_NO_WARNINGS b[i] = bs[[Link]() - 1 - i] - ’0’;
#pragma comment(linker, ”/STACK:167772160000”) }
#include <iostream> FFT::fft(a, fa);
#include <iomanip> FFT::fft(b, fb);
#include <fstream> FOR(i, 0, FFT::pwrN) {
#include <cstdio> fc[i] = fa[i] * fb[i];
#include <cstdlib> }
#include <cassert> // turn [0,1,2,...,n-1] into [0, n-1, n-2, ..., 1]
#include <climits> FOR(i, 1, FFT::pwrN) {
#include <cmath> if (i < FFT::pwrN - i) {
#include <algorithm> swap(fc[i], fc[FFT::pwrN - i]);
#include <cstring> }
#include <string> }
#include <vector> FFT::fft(fc, cc);
#include <list> ll carry = 0;
#include <stack> vector<int> v;
#include <set> FOR(i, 0, FFT::pwrN) {
#include <bitset> int num = round(cc[i].real() / FFT::pwrN) + carry;
#include <queue> [Link](num % 10);
#include <map> carry = num / 10;
#include <sstream> }
#include <functional> while (carry > 0) {
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 16 of 23

[Link](carry % 10); 6.4 Sprague Grundy Theorem


carry /= 10;
} We have a game which fulfills the following require-
reverse([Link](), [Link]());
bool start = false; ments:
ostringstream ss; • There are two players who move alternately.
bool allZero = true;
for (auto x : v) { • The game consists of states, and the possible
if (x != 0) { moves in a state do not depend on whose turn
allZero = false;
break; it is.
} • The game ends when a player cannot make a
}
if (sgn1*sgn2 < 0 && !allZero) ss << ”-”; move.
for (auto x : v) { • The game surely ends sooner or later.
if (x == 0 && !start) continue;
start = true; • The players have complete information about
ss << abs(x); the states and allowed moves, and there is no
}
if (!start) ss << 0; randomness in the game.
return [Link](); Grundy Numbers. The idea is to calculate
}
Grundy numbers for each game state. It is calculated
like so: mex({g1 , g2 , ..., gn }), where g1 , g2 , ..., gn are
the Grundy numbers of the states which are reach-
6.3 FFT able from the current state. mex gives the small-
est nonnegative number that is not in the set
namespace FFT {
int n; (mex({0, 1, 3}) = 2, mex(∅) = 0). If the Grundy
vector<int> r; number of a state is 0, then this state is a losing
vector<complex<ld>> omega;
int logN, pwrN; state. Otherwise it’s a winning state.
Grundy’s Game. Sometimes a move in a game
void initLogN() {
logN = 0; divides the game into subgames that are indepen-
pwrN = 1; dent of each other. In this case, the Grundy num-
while (pwrN < n) {
pwrN *= 2; ber of a game state is mex({g1 , g2 , ..., gn }), gk =
logN++; ak,1 ⊕ ak,2 ⊕ ... ⊕ ak,m meaning that move k divides
}
n = pwrN; the game into m subgames whose Grundy numbers
} are ai,j .
void initOmega() { Example. We have a heap with n sticks. On
FOR(i, 0, pwrN) { each turn, the player chooses a heap and divides it
omega[i] = { cos(2 * i*PI / n), sin(2 * i*PI / n) };
} into two nonempty heaps such that the heaps are
} of different size. The player who makes the last
void initR() { move wins the game. Let g(n) denote the Grundy
r[0] = 0; number of a heap of size n. The Grundy num-
FOR(i, 1, pwrN) {
r[i] = r[i / 2] / 2 + ((i & 1) << (logN - 1)); ber can be calculated by going though all possi-
} ble ways to divide the heap into two parts. E.g.
}
g(8) = mex({g(1) ⊕ g(7), g(2) ⊕ g(6), g(3) ⊕ g(5)}).
void initArrays() { Base case: g(1) = g(2) = 0, because these are losing
[Link]();
[Link](pwrN); states. All other solutions can be found like this:
[Link]();
b a
x′ = x − k , y ′ = y + k , k ∈ Z
[Link](pwrN);
}
g g
void init(int n) {
FFT::n = n;
initLogN();
initArrays();
initOmega(); 6.5 Burnside’s Lemma
initR();
} Let G be a finite group that acts on a set X. For
each g in G let X g denote the set of elements in X
void fft(complex<ld> a[], complex<ld> f[]) {
FOR(i, 0, pwrN) { that are fixed by g. Burnside’s lemma asserts the
f[i] = a[r[i]]; following formula for the number of orbits:
}
for (ll k = 1; k < pwrN; k *= 2) {
1 ∑ g
for (ll i = 0; i < pwrN; i += 2 * k) { |X/G| = |X |.
for (ll j = 0; j < k; j++) { |G|
auto z = omega[j*n / (2 * k)] * f[i + j + k]; g∈G
f[i + j + k] = f[i + j] - z;
f[i + j] += z;
} Example. Coloring a cube with three colors.
}
} Let X be the set of 36 possible face color combina-
}
} tions. Let’s count the sizes of the fixed sets for each
of the 24 rotations:
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 17 of 23

• one 0-degree rotation which leaves all 36 ele- 6.7 Chinese Remainder Theorem
ments of X unchanged
• six 90-degree face rotations, each of which Let’s say we have some numbers m
∏i , which are all
leaves 33 elements of X unchanged mutually coprime. Also, let M = i mi . Then the
• three 180-degree face rotation, each of which system of congruences
leaves 34 elements of X unchanged 
• eight 120-degree vertex rotations, each of  x ≡ a1


(mod m1 )
x ≡ a2 (mod m2 )
which leaves 32 elements of X unchanged

 ...
• six 180-degree edge rotations, each of which 
x ≡ ak (mod mk )
leaves 33 elements of X unchanged
1
The average is then 24 (36 + 6· 33 + 3· 34 + 8· 32 + is equivalent to x ≡ A (mod M ) and there exists
1
6· 33 ) = 57. For n colors: 24 (n6 + 3n4 + 12n3 + 8n2 ). a unique number A satisfying 0 ≤ A ≤ M .
Solution for two: x ≡ a1 (mod m1 ), x ≡ a2
Example. Coloring a circular stripe of n cells (mod m2 ). Let x = a1 + km1 . Substituting into
with two colors. the second congruence: km1 ≡ a2 − a1 (mod m2 ).
Then, k = (m1 )−1m2 (a2 − a1 ) (mod m2 ). and we can
X is the set of all colored striped (it has 2n ele- easily find x. This can be extended to multiple equa-
ments), G is the group of rotations (n elements - by tions by solving them one-by-one.
0 cells, by 1 cell, ..., by (n − 1) cells). Let’s fix some If the moduli are not coprime, solve the system
K and find the number of stripes that are fixed by y ≡ 0 (mod mg1 ), y ≡ a2 −a
g
1
(mod mg2 ) for y. Then
the rotation by K cells. If a stripe becomes itself let x ≡ gy + a1 (mod g ).
m1 m2

after rotation by K cells, then its 1st cell must have


the same color as its (1 + K mod n)-th cell, which
is in turn the same as its (1 + 2K mod n)-th cell, 6.8 Gaussian Elimination
etc., until mK mod n = 0. This will happen when
// The last column of a is the right-hand side of the system.
m = n/gcd(K, n). Therefore, we have n/gcd(K, n) // Returns 0, 1 or oo - the number of solutions.
cells that must all be of the same color. The same // If at least one solution is found, it will be in ans
int gauss (vector < vector<ld> > a, vector<ld> & ans) {
will happen when starting from the second cell and so int n = (int) [Link]();
on. Therefore, all cells are separated into gcd(K, n) int m = (int) a[0].size() - 1;
groups, with each group being of one color, and that vector<int> where (m, -1);
yields 2gcd(K,n) choices. That’s
∑n−1 why the answer to
for (int col=0, row=0; col<m && row<n; ++col) {
int sel = row;
the original problem is n1 k=0 2gcd(k,n) . for (int i=row; i<n; ++i)
if (abs (a[i][col]) > abs (a[sel][col]))
sel = i;
if (abs (a[sel][col]) < eps)
6.6 Extended Euclidean Algorithm continue;
for (int i=col; i<=m; ++i)
swap (a[sel][i], a[row][i]);
// ax+by=gcd(a,b) where[col] = row;
void solveEq(ll a, ll b, ll& x, ll& y, ll& g) {
if(b==0) { for (int i=0; i<n; ++i)
x = 1; if (i != row) {
y = 0; ld c = a[i][col] / a[row][col];
g = a; for (int j=col; j<=m; ++j)
return; a[i][j] -= a[row][j] * c;
} }
ll xx, yy; ++row;
solveEq(b, a%b, xx, yy, g); }
x = yy;
y = xx-yy*(a/b); [Link] (m, 0);
} for (int i=0; i<m; ++i)
// ax+by=c if (where[i] != -1)
bool solveEq(ll a, ll b, ll c, ll& x, ll& y, ll& g) { ans[i] = a[where[i]][m] / a[where[i]][i];
solveEq(a, b, x, y, g); for (int i=0; i<n; ++i) {
if(c%g != 0) return false; ld sum = 0;
x *= c/g; y *= c/g; for (int j=0; j<m; ++j)
return true; sum += ans[j] * a[i][j];
} if (abs (sum - a[i][m]) > eps)
// Finds a solution (x, y) so that x >= 0 and x is minimal return 0;
bool solveEqNonNegX(ll a, ll b, ll c, ll& x, ll &y, ll& g) { }
if(!solveEq(a, b, c, x, y, g)) return false;
ll k = x*g/b; for (int i=0; i<m; ++i)
x = x - k*b/g; if (where[i] == -1)
y = y + k*a/g; return oo;
if(x < 0) { return 1;
x += b/g; }
y -= a/g;
}
return true;
} 6.9 Linear Sieve
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 18 of 23

ll minDiv[MAXN+1]; }
vector<ll> primes; }

void sieve(ll n){ void initR() {


FOR(k, 2, n+1){ r[0] = 0;
minDiv[k] = k; FOR(i, 1, pwrN) {
} r[i] = r[i / 2] / 2 + ((i & 1) << (logN - 1));
FOR(k, 2, n+1) { }
if(minDiv[k] == k) { }
[Link](k);
} void initArrays() {
for(auto p : primes) { [Link]();
if(p > minDiv[k]) break; [Link](pwrN);
if(p*k > n) break; [Link]();
minDiv[p*k] = p; [Link](pwrN);
} }
}
} void init(ll n) {
FFT::n = n;
initLogN();
initArrays();
6.10 Simpson Integration initOmega();
initR();
}
const int N = 1000 * 1000; // number of steps (already
multiplied by 2) void fft(ll a[], ll f[]) {
for (ll i = 0; i < pwrN; i++) {
double simpsonIntegration(double a, double b){ f[i] = a[r[i]];
double h = (b - a) / N; }
double s = f(a) + f(b); // a = x_0 and b = x_2n for (ll k = 1; k < pwrN; k *= 2) {
for (int i = 1; i <= N - 1; ++i) { for (ll i = 0; i < pwrN; i += 2 * k) {
double x = a + h * i; for (ll j = 0; j < k; j++) {
s += f(x) * ((i & 1) ? 4 : 2); auto z = omega[j*n / (2 * k)] * f[i + j + k] %
} M;
s *= h / 3; f[i + j + k] = f[i + j] - z;
return s; f[i + j] += z;
} f[i + j + k] %= M;
if (f[i + j + k] < 0) f[i + j + k] += M;
f[i + j] %= M;
}
6.11 FFT With Modulo }
}
}
bool isGenerator(ll g) { }
if (pwr(g, M - 1) != 1) return false;
for (ll i = 2; i*i <= M - 1; i++) {
if ((M - 1) % i == 0) {
ll q = i; 6.12 Euler Totient Function
if (isPrime(q)) {
ll p = (M - 1) / q;
// Number of numbers x < n so that gcd(x, n) = 1
ll pp = pwr(g, p);
ll phi(ll n) {
if (pp == 1) return false;
if(n == 1) return 1;
}
auto f = factorize(n);
q = (M - 1) / i;
ll res = n;
if (isPrime(q)) {
for(auto p : f) {
ll p = (M - 1) / q;
res = res - res/[Link];
ll pp = pwr(g, p);
}
if (pp == 1) return false;
return res;
}
}
}
}
return true;
}
6.13 Modular Inverse
namespace FFT {
ll n; bool invWithEuclid(ll a, ll m, ll& aInv) {
vector<ll> r; ll x, y, g;
vector<ll> omega; if(!solveEqNonNegX(a, m, 1, x, y, g)) return false;
ll logN, pwrN; aInv = x;
return true;
void initLogN() { }
logN = 0; // Works only if m is prime
pwrN = 1; ll invFermat(ll a, ll m) {
while (pwrN < n) { return pwr(a, m-2, m);
pwrN *= 2; }
logN++; // Works only if gcd(a, m) = 1
} ll invEuler(ll a, ll m) {
n = pwrN; return pwr(a, phi(m)-1, m);
} }

void initOmega() {
ll g = 2;
while (!isGenerator(g)) g++; 6.14 Factorization With Sieve
ll G = 1;
g = pwr(g, (M - 1) / pwrN); // Use linear sieve to calculate minDiv
FOR(i, 0, pwrN) { vector<pll> factorize(ll x) {
omega[i] = G; vector<pll> res;
G *= g; ll prev = -1;
G %= M; ll cnt = 0;
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 19 of 23

while(x != 1) { bool leftToRight = true;


ll d = minDiv[x]; int round = 0;
if(d == prev) {
cnt++; while (round < (int)[Link]() && (int)[Link]() < len) {
} else { int step = d[round];
if(prev != -1) [Link]({prev, cnt}); if (leftToRight) {
prev = d; int count = 0;
cnt = 1; for (int i = 0; i < len; i++) {
} if (!filled[i]) {
x /= d; count++;
} if (count == step) {
[Link]({prev, cnt}); order.push_back(i);
return res; filled[i] = true;
} count = 0;
if ((int)[Link]() == len) break;
}
}
}
7 Pracitce Solutions } else {
int count = 0;
for (int i = len - 1; i >= 0; i--) {
7.1 H if (!filled[i]) {
count++;
if (count == step) {
#include <bits/stdc++.h> order.push_back(i);
using namespace std; filled[i] = true;
count = 0;
int main() { if ((int)[Link]() == len) break;
ios::sync_with_stdio(false); }
[Link](nullptr); }
}
int r, c; }
cin >> r >> c; leftToRight = !leftToRight;
vector<string> grid(r); round++;
for (int i = 0; i < r; i++) { }
cin >> grid[i];
} // Remaining letters (d = 1)
if ((int)[Link]() < len) {
// Directions for the 8 neighbors if (leftToRight) {
int dr[8] = {-1,-1,-1,0,0,1,1,1}; for (int i = 0; i < len; i++) if (!filled[i]) order.
int dc[8] = {-1,0,1,-1,1,-1,0,1}; push_back(i);
} else {
int countLocations = 0; for (int i = len - 1; i >= 0; i--) if (!filled[i]) order.
int ansRow = -1, ansCol = -1; push_back(i);
}
for (int i = 0; i < r; i++) { }
for (int j = 0; j < c; j++) { return order;
if (grid[i][j] == ’0’) { // possible treasure center }
bool surrounded = true;
for (int k = 0; k < 8; k++) { int main() {
int ni = i + dr[k], nj = j + dc[k]; ios::sync_with_stdio(false);
if (ni < 0 || nj < 0 || ni >= r || nj >= c || [Link](nullptr);
grid[ni][nj] != ’O’) {
surrounded = false; char mode;
break; string key;
} string text;
} cin >> mode >> key;
if (surrounded) { [Link]();
countLocations++; getline(cin, text);
ansRow = i + 1; // convert to 1-based
indexing // Convert key to steps
ansCol = j + 1; vector<int> d;
} for (char c : key) d.push_back((c - ’a’) + 2);
}
} if (mode == ’E’) {
} // 1. Clean plaintext
string clean;
if (countLocations == 0) { for (char c : text) {
cout << ”Oh␣no!\n”; if (isalpha(c)) clean.push_back(tolower(c));
} else if (countLocations == 1) { }
cout << ansRow << ”␣” << ansCol << ”\n”;
} else { int len = [Link]();
cout << ”Oh␣no!␣” << countLocations << ”␣locations\ vector<int> order = get_order(len, d);
n”; string cipher(len, ’?’);
}
return 0; for (int i = 0; i < len; i++) {
} cipher[order[i]] = clean[i];
}
cout << cipher << ”\n”;
} else { // Decrypt
7.2 F int len = [Link]();
vector<int> order = get_order(len, d);
string plain(len, ’?’);
#include <bits/stdc++.h>
using namespace std; for (int i = 0; i < len; i++) {
plain[i] = text[order[i]];
vector<int> get_order(int len, const vector<int>& d) { }
vector<int> order; cout << plain << ”\n”;
vector<bool> filled(len, false);
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 20 of 23

} /*
Let’s say we have a relation:
return 0; dp[i] = min(dp[j] + h[j+1]*w[i]) for j<=i
} Let’s set k_j = h[j+1], x = w[i], b_j = dp[j]. We get:
dp[i] = min(b_j+k_j*x) for j<=i.
This is the same as finding a minimum point on a set of lines.
After calculating the value, we add a new line with
7.3 B k_i = h[i+1] and b_i = dp[i].
*/
#include <bits/stdc++.h> struct Line {
int k;
using namespace std; int b;
using int64 = long long;
int eval(int x) {
long long mygcd(long long a, long long b) { return k*x+b;
while (b) { }
long long t = a % b;
a = b; int intX(Line& other) {
b = t; int x = b-other.b;
} int y = other.k-k;
return a; int res = x/y;
} if(x%y != 0) res++;
return res;
}
int main() { };
ios::sync_with_stdio(false);
[Link](nullptr); struct BagOfLines {
vector<pair<Line, int>> lines;
string s;
cin >> s; void addLine(int k, int b) {
int n = [Link](); Line current = {k, b};
vector<int> a(n); if([Link]()) {
for (int i = 0; i < n; i++) a[i] = s[i] - ’0’; [Link]({current, -OO});
return;
vector<int> prevGreater(n, -1), nextGreater(n, n); }
stack<int> st; int x = -OO;
while(true) {
// prevGreater auto line = [Link]().first;
for (int i = 0; i < n; i++) { int from = [Link]().second;
while (![Link]() && a[[Link]()] <= a[i]) [Link](); x = [Link](current);
if (![Link]()) prevGreater[i] = [Link](); if(x > from) break;
[Link](i); lines.pop_back();
} }
[Link]({current, x});
while (![Link]()) [Link](); }

// nextGreater int findMin(int x) {


for (int i = n - 1; i >= 0; i--) { int lo = 0, hi = (int)[Link]()-1;
while (![Link]() && a[[Link]()] < a[i]) [Link](); while(lo < hi) {
if (![Link]()) nextGreater[i] = [Link](); int mid = (lo+hi+1)/2;
[Link](i); if(lines[mid].second <= x) {
} lo = mid;
} else {
__int128 totalSum = 0; hi = mid-1;
for (int i = 0; i < n; i++) { }
long long left = i - prevGreater[i]; }
long long right = nextGreater[i] - i; return lines[lo].[Link](x);
totalSum += (__int128)a[i] * left * right; }
} };

long long totalSubstrings = (long long)n * (n + 1) / 2;

long long num = (long long)totalSum; 8.2 Divide And Conquer


long long den = totalSubstrings;
/*
long long g = mygcd(num, den); Let A[i][j] be the optimal answer for using i objects to satisfy j
num /= g; first
den /= g; requirements.
The recurrence is:
if (num % den == 0) { A[i][j] = min(A[i-1][k] + f(i, j, k)) where f is some function that
cout << num / den << ”\n”; denotes the
} else if (num > den) { cost of satisfying requirements from k+1 to j using the i-th
cout << num / den << ”␣” << (num % den) << ”/” object.
<< den << ”\n”; Consider the recursive function calc(i, jmin, jmax, kmin, kmax),
} else { that calculates
cout << num << ”/” << den << ”\n”; all A[i][j] for all j in [jmin, jmax] and a given i using known A[i
} -1][*].
*/
return 0;
} void calc(int i, int jmin, int jmax, int kmin, int kmax) {
if(jmin > jmax) return;
int jmid = (jmin+jmax)/2;
// calculate A[i][jmid] naively (for k in kmin...min(jmid,
8 Dynamic Programming kmax){...})
// let kmid be the optimal k in [kmin, kmax]
calc(i, jmin, jmid-1, kmin, kmid);
8.1 Convex Hull Trick calc(i, jmid+1, jmax, kmid, kmax);
}
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 21 of 23

}
int main() {
// set initial dp values
FOR(i, start, k+1){
calc(i, 0, n-1, 0, n-1);
} 9.2 KMP
cout << dp[k][n-1];
}
// Knuth-Morris-Pratt algorithm
vector<int> findOccurences(const string& s, const string& t) {
int n = [Link]();
8.3 Optimizations int m = [Link]();
string S = s + ”#” + t;
auto pi = prefixFunction(S);
1. Convex Hull 1: vector<int> ans;
• Recurrence: dp[i] = minj<i {dp[j] + FOR(i, n+1, n+m+1) {
if(pi[i] == n) {
b[j]· a[i]} [Link](i-2*n);
• Condition: b[j] ≥ b[j + 1], a[i] ≤ a[i + 1] }
}
• Complexity: O(n2 ) → O(n) return ans;
2. Convex Hull 2: }
• Recurrence: dp[i][j] = mink<j {dp[i −
1][k] + b[k]· a[j]}
• Condition: b[k] ≥ b[k + 1], a[j] ≤ a[j + 1] 9.3 Prefix Function
• Complexity: O(kn2 ) → O(kn)
3. Divide and Conquer: // pi[i] is the length of the longest proper prefix of the substring
• Recurrence: dp[i][j] = mink<j {dp[i − s[0..i] which is also a suffix
// of this substring
1][k] + C[k][j]} vector<int> prefixFunction(const string& s) {
• Condition: A[i][j] ≤ A[i][j + 1] int n = (int)[Link]();
vector<int> pi(n);
• Complexity: O(kn2 ) → O(kn log(n)) for (int i = 1; i < n; i++) {
4. Knuth: int j = pi[i-1];
while (j > 0 && s[i] != s[j])
• Recurrence: dp[i][j] = mini<k<j {dp[i][k]+ j = pi[j-1];
dp[k][j]} + C[i][j] if (s[i] == s[j])
j++;
• Condition: A[i][j − 1] ≤ A[i][j] ≤ A[i + pi[i] = j;
1][j] }
return pi;
• Complexity: O(n3 ) → O(n2 ) }
Notes:
• A[i][j] - the smallest k that gives the optimal
answer
• C[i][j] - some given cost function 9.4 Prefix Sum Array 2d

// 2D Prefix Sum (Matrix)


9 Strings vector<vector<long long>> prefixSum2D(const vector<vector<
int>>& mat) {
int n = [Link](), m = mat[0].size();
vector<vector<long long>> pref(n + 1, vector<long long>(
9.1 Prefix Function Automaton m + 1, 0));
for (int i = 1; i <= n; i++) {
// aut[oldPi][c] = newPi for (int j = 1; j <= m; j++) {
vector<vector<int>> computeAutomaton(string s) { pref[i][j] = mat[i-1][j-1]
const char BASE = ’a’; + pref[i-1][j]
s += ”#”; + pref[i][j-1]
int n = [Link](); - pref[i-1][j-1];
vector<int> pi = prefixFunction(s); }
vector<vector<int>> aut(n, vector<int>(26)); }
for (int i = 0; i < n; i++) { return pref;
for (int c = 0; c < 26; c++) { }
if (i > 0 && BASE + c != s[i])
aut[i][c] = aut[pi[i-1]][c]; // Query sum of submatrix [(x1,y1)..(x2,y2)] (0-indexed)
else long long rangeSum2D(const vector<vector<long long>>& pref
aut[i][c] = i + (BASE + c == s[i]); , int x1, int y1, int x2, int y2) {
} return pref[x2+1][y2+1]
} - pref[x1][y2+1]
return aut; - pref[x2+1][y1]
} + pref[x1][y1];
vector<int> findOccurs(const string& s, const string& t) { }
auto aut = computeAutomaton(s);
int curr = 0; // Usage
vector<int> occurs; vector<vector<int>> mat = {
FOR(i, 0, (int)[Link]()) { {1, 2, 3},
int c = t[i]-’a’; {4, 5, 6},
curr = aut[curr][c]; {7, 8, 9}
if(curr == (int)[Link]()) { };
[Link]([Link]()+1); auto pref = prefixSum2D(mat);
} cout << rangeSum2D(pref, 1, 1, 2, 2); // sum of submatrix
} [(1,1)..(2,2)] = 5+6+8+9 = 28
return occurs;
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 22 of 23

9.5 Aho Corasick Automaton }


walkUp(getExitLink(v), matches);
}
// alphabet size
const int K = 70; // returns the IDs of matched strings.
// Will contain duplicates if multiple matches of the same string
// the indices of each letter of the alphabet are found.
int intVal[256]; vector<int> walk(const string& s) {
void init() { vector<int> matches;
int curr = 2; int curr = 0;
intVal[1] = 1; for(char c : s) {
for(char c = ’0’; c <= ’9’; c++, curr++) intVal[(int)c] = curr = go(curr, c);
curr; if(!t[curr].[Link]()) {
for(char c = ’A’; c <= ’Z’; c++, curr++) intVal[(int)c] = for(auto m : t[curr].marks) [Link](m);
curr; }
for(char c = ’a’; c <= ’z’; c++, curr++) intVal[(int)c] = walkUp(getExitLink(curr), matches);
curr; }
} return matches;
}
struct Vertex { /* Usage:
int next[K]; * addString(strs[i], i);
vector<int> marks; * auto matches = walk(text);
// ^ this can be changed to int mark = -1, if there will be * .. do what you need with the matches - count, check if some
no duplicates id exists, etc ..
int p = -1; * Some applications:
char pch; * - Find all matches: just use the walk function
int link = -1; * - Find lexicographically smallest string of a given length that
int exitLink = -1; doesn’t match any of the given strings:
// ^ exitLink points to the next node on the path of suffix * For each node, check if it produces any matches (it either
links which is marked contains some marks or walkUp(v) returns some marks).
int go[K]; * Remove all nodes which produce at least one match. Do DFS
in the remaining graph, since none of the remaining
// ch has to be some small char nodes
Vertex(int _p=-1, char ch=(char)1) : p(_p), pch(ch) { * will ever produce a match and so they’re safe.
fill(begin(next), end(next), -1); * - Find shortest string containing all given strings:
fill(begin(go), end(go), -1); * For each vertex store a mask that denotes the strings which
} match at this state. Start at (v = root, mask = 0),
}; * we need to reach a state (v, mask=2^n-1), where n is the
number of strings in the set. Use BFS to transition
vector<Vertex> t(1); between states
* and update the mask.
void addString(string const& s, int id) { */
int v = 0;
for (char ch : s) {
int c = intVal[(int)ch];
if (t[v].next[c] == -1) {
t[v].next[c] = [Link]();
9.6 Suffix Array
t.emplace_back(v, ch);
} vector<int> sortCyclicShifts(string const& s) {
v = t[v].next[c]; int n = [Link]();
} const int alphabet = 256; // we assume to use the whole
t[v].[Link](id); ASCII range
} vector<int> p(n), c(n), cnt(max(alphabet, n), 0);
for (int i = 0; i < n; i++)
int go(int v, char ch); cnt[s[i]]++;
for (int i = 1; i < alphabet; i++)
int getLink(int v) { cnt[i] += cnt[i-1];
if (t[v].link == -1) { for (int i = 0; i < n; i++)
if (v == 0 || t[v].p == 0) p[--cnt[s[i]]] = i;
t[v].link = 0; c[p[0]] = 0;
else int classes = 1;
t[v].link = go(getLink(t[v].p), t[v].pch); for (int i = 1; i < n; i++) {
} if (s[p[i]] != s[p[i-1]])
return t[v].link; classes++;
} c[p[i]] = classes - 1;
}
int getExitLink(int v) { vector<int> pn(n), cn(n);
if(t[v].exitLink != -1) return t[v].exitLink; for (int h = 0; (1 << h) < n; ++h) {
int l = getLink(v); for (int i = 0; i < n; i++) {
if(l == 0) return t[v].exitLink = 0; pn[i] = p[i] - (1 << h);
if(!t[l].[Link]()) return t[v].exitLink = l; if (pn[i] < 0)
return t[v].exitLink = getExitLink(l); pn[i] += n;
} }
fill([Link](), [Link]() + classes, 0);
int go(int v, char ch) { for (int i = 0; i < n; i++)
int c = intVal[(int)ch]; cnt[c[pn[i]]]++;
if (t[v].go[c] == -1) { for (int i = 1; i < classes; i++)
if (t[v].next[c] != -1) cnt[i] += cnt[i-1];
t[v].go[c] = t[v].next[c]; for (int i = n-1; i >= 0; i--)
else p[--cnt[c[pn[i]]]] = pn[i];
t[v].go[c] = v == 0 ? 0 : go(getLink(v), ch); cn[p[0]] = 0;
} classes = 1;
return t[v].go[c]; for (int i = 1; i < n; i++) {
} pair<int, int> cur = {c[p[i]], c[(p[i] + (1 << h)) % n
]};
void walkUp(int v, vector<int>& matches) { pair<int, int> prev = {c[p[i-1]], c[(p[i-1] + (1 << h))
if(v == 0) return; % n]};
if(!t[v].[Link]()) { if (cur != prev)
for(auto m : t[v].marks) [Link](m); ++classes;
Kardan University (Mohammad Masoom Wahid, Ahmad Sohail Raoufi, Said Yousuf Said) 23 of 23

cn[p[i]] = classes - 1;
}
[Link](cn);
}
return p;
}
vector<int> constructSuffixArray(string s) {
s += ”$”; // <- this must be smaller than any character in
s
vector<int> sorted_shifts = sortCyclicShifts(s);
sorted_shifts.erase(sorted_shifts.begin());
return sorted_shifts;
}

9.7 Prefix Sum Array 1d


// Prefix Sum Array (1D)
vector<long long> prefixSum(const vector<int>& arr) {
int n = [Link]();
vector<long long> pref(n + 1, 0); // pref[0] = 0
for (int i = 1; i <= n; i++) {
pref[i] = pref[i - 1] + arr[i - 1];
}
return pref;
}

// Query sum of arr[l..r] in O(1) (0-indexed)


long long rangeSum(const vector<long long>& pref, int l, int r)
{
return pref[r + 1] - pref[l];
}

// Usage
vector<int> arr = {1, 2, 3, 4, 5};
auto pref = prefixSum(arr);
cout << rangeSum(pref, 1, 3); // sum of arr[1..3] = 2+3+4 = 9

9.8 Hashing
struct HashedString {
const ll A1 = 999999929, B1 = 1000000009, A2 =
1000000087, B2 = 1000000097;
vector<ll> A1pwrs, A2pwrs;
vector<pll> prefixHash;
HashedString(const string& _s) {
init(_s);
calcHashes(_s);
}
void init(const string& s) {
ll a1 = 1;
ll a2 = 1;
FOR(i, 0, (int)[Link]()+1) {
[Link](a1);
[Link](a2);
a1 = (a1*A1)%B1;
a2 = (a2*A2)%B2;
}
}
void calcHashes(const string& s) {
pll h = {0, 0};
[Link](h);
for(char c : s) {
ll h1 = ([Link]().first*A1 + c)%B1;
ll h2 = ([Link]().second*A2 + c)%B2;
[Link]({h1, h2});
}
}
pll getHash(int l, int r) {
ll h1 = (prefixHash[r+1].first - prefixHash[l].first*A1pwrs
[r+1-l]) % B1;
ll h2 = (prefixHash[r+1].second - prefixHash[l].second*
A2pwrs[r+1-l]) % B2;
if(h1 < 0) h1 += B1;
if(h2 < 0) h2 += B2;
return {h1, h2};
}
};

You might also like