ACM-ICPC Reference Guide for Kardan University
ACM-ICPC Reference Guide for Kardan University
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
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
}; 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);
}
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 });
}
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
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 };
);
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;
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; }
}
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
)
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
• 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
ll minDiv[MAXN+1]; }
vector<ll> primes; }
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
} /*
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](); }
}
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
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;
}
// 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};
}
};