Notebook PDF
Notebook PDF
1
MO,Radovinović, Sindičić
Edge &e = E[g[u][i]]; // }
Edge &oe = E[g[u][i]ˆ1]; // Running time: // BEGIN CUT
if (d[e.v] == d[e.u] + 1) { // O(|V|ˆ3) // The following code solves UVA
LL amt = e.cap - e.flow; if (flow // problem #10989: Bomb, Divide and
!= -1 && amt > // INPUT: Conquer
flow) amt = flow; // - graph, constructed using int main() {
if (LL pushed = DFS(e.v, T, amt)) { AddEdge() int N;
// cin >> N;
e.flow += pushed; // OUTPUT:
oe.flow -= pushed; // - (min cut value, nodes in half of min for (int i = 0; i < N; i++) { int n, m;
return pushed; cut) cin >> n >> m;
} vvi weights(n, vi(n));
} #include "template.h"
} typedef vector<vi> vvi; const int for (int j = 0; j < m; j++) { int a, b, c;
return 0;
} INF = 1000000000; cin >> a >> b >> c;
LL MaxFlow(int S, int T) { LL total pair<int, vi> GetMinCut(vvi & weights) weights[a-1][b-1] = weights[b -1][a-1] = c;
= 0; { }
while (BFS(S, T)) { int N = weights.size(); pair<int, vi> res = GetMinCut( weights);
fill(pt.begin(), pt.end(), 0)
; vi used(N), cut, best_cut; int
while (LL flow = DFS(S, T)) best_weight = -1; cout << "Case #" << i+1 << ": "
total += flow; for (int phase = N-1; phase >= 0; phase--) { << res.first << endl;
} }
return total; }
vi w = weights[0]; // END CUT
} vi added = used;
}; int prev, last = 0;
// BEGIN CUT for (int i = 0; i < phase; i++)
{ 1.3 Min cost Max Flow
// The following code solves SPOJ problem
prev = last; last // Implementation of min cost max flow
#4110: Fast Maximum Flow (FASTFLOW) = -1; algorithm using adjacency
int main() for (int j = 1; j < N; j++) if (!added[j] // matrix (Edmonds and Karp 1972). This
{ && (last == -1 || w[j] > w[last])) implementation keeps track of
int N, E;
scanf("%d%d", &N, &E); Dinic last = j; // forward and reverse edges separately (so
dinic(N); if (i == phase-1) { you can set cap[i ][j] !=
for(int i = 0; i < E; i++) for (int j = 0; j < N; j++)
{ weights[prev][j] += // cap[j][i]). For a regular max flow, set all
int u, v; weights[last][j]; edge costs to 0.
LL cap; for (int j = 0; j < N; j++) //
scanf("%d%d%lld", &u, &v, &cap)
; weights[j][prev] = // Running time, O(|V|ˆ2) cost per
weights[prev][j]; augmentation
dinic.AddEdge(u - 1, v - 1, cap ); used[last] = true; // max flow: O(|V|ˆ3)
dinic.AddEdge(v - 1, u - 1, cap ); cut.push_back(last); augmentations
if (best_weight == -1 || w[ last] <
} // min cost max flow: O(|V|ˆ4 *
best_weight) { MAX_EDGE_COST) augmentations
printf("%lld\n", dinic.MaxFlow(0, N - 1)); best_cut = cut;
best_weight = w[last]; //
return 0; } // INPUT:
} } else { // - graph, constructed using
// END CUT for (int j = 0; j < N; j++) w[j] += AddEdge()
weights[last][j]; // - source
added[last] = true; // - sink
} //
1.2 Global min-cut } // OUTPUT:
} // - (maximum flow value,
// Adjacency matrix implementation of minimum cost value)
return make_pair(best_weight,
Stoer-Wagner min cut algorithm. best_cut); // - To obtain the actual flow, look at
2
positive values only.
MO,Radovinović, Sindičić
Relax(s, k, cap[s][k] - flow[s][k], mcmf.AddEdge(int(v[i][1]),
#include <cmath> cost[s][k], 1); int(v[i][0]), K, v[i][2]);
#include <vector> }
#include <iostream> Relax(s, k, flow[k][s], - cost[k][s], - mcmf.AddEdge(0, 1, D, 0);
using namespace std; 1);
if (best == -1 || dist[k] < pair<L, L> res = mcmf.
typedef vector<int> VI; typedef dist[best]) best = k; GetMaxFlow(0, N);
vector<VI> VVI; typedef long long } if (res.first == D) {
s = best; printf("%Ld\n", res.second);
L; typedef vector<L> VL; typedef } } else {
vector<VL> VVL; typedef pair<int, for (int k = 0; k < N; k++) printf("Impossible.\n");
int> PII; typedef vector<PII> VPII; pi[k] = min(pi[k] + dist[k], }
INF); }
const L INF = numeric_limits<L>:: return width[t]; return 0;
max() / 4; } }
struct MinCostMaxFlow { int pair<L, L> GetMaxFlow(int s, int t) { // END CUT
N;
VVL cap, flow, cost; VI L totflow = 0, totcost = 0; while (L amt =
found; Dijkstra(s, t))
VL dist, pi, width; { 2 Geometry
VPII dad; totflow += amt;
MinCostMaxFlow(int N) : for (int x = t; x != s; x = dad[x].first) { 2.1 Convex hull
N(N), cap(N, VL(N)), flow(N, VL (N)), if (dad[x].second == 1) {
cost(N, VL(N)), // Compute the 2D convex hull of a set of
found(N), dist(N), pi(N), width (N), dad(N) flow[dad[x].first][x] += amt; points using the monotone
{} chain
void AddEdge(int from, int to, L cap, L totcost += amt * cost[dad [x].first][x]; // algorithm. Eliminate redundant points
cost) { } else { flow[x][dad[x].first] -= from the hull if REMOVE_REDUNDANT
this->cap[from][to] = cap; this- is
amt; // #defined.
>cost[from][to] = cost; totcost -= amt * cost[x][ //
} dad[x].first]; // Running time: O(n log n)
void Relax(int s, int k, L cap, L cost, int dir) } //
{ }
} // INPUT: a vector of input points,
L val = dist[s] + pi[s] - pi[k] unordered.
+ cost; return make_pair(totflow, totcost); // OUTPUT: a vector of points in
if (cap && val < dist[k]) { dist[k] = } the convex hull,
val; }; counterclockwise, starting
dad[k] = make_pair(s, dir); width[k] =
min(cap, width[s]) // BEGIN CUT // with bottommost/ leftmost point
; // The following code solves UVA
} problem #10594: Data Flow #include <cstdio>
} #include <cassert>
int main() { #include <vector>
L Dijkstra(int s, int t) { int N, M;
fill(found.begin(), found.end() #include <algorithm>
, false); while (scanf("%d%d", &N, &M) == 2) { #include <cmath>
fill(dist.begin(), dist.end(), INF); // BEGIN CUT
VVL v(M, VL(3)); #include <map>
fill(width.begin(), width.end() for (int i = 0; i < M; i++) // END CUT
, 0); scanf("%Ld%Ld%Ld", &v[i][0], using namespace std;
dist[s] = 0; width[s] = &v[i][1], &v[i][2]);
INF; L D, K; #define REMOVE_REDUNDANT
scanf("%Ld%Ld", &D, &K); typedef double T;
while (s != -1) { MinCostMaxFlow mcmf(N+1); for (int i
int best = -1; const T EPS = 1e-7;
found[s] = true; = 0; i < M; i++) { struct PT {
for (int k = 0; k < N; k++) { if (found[k]) mcmf.AddEdge(int(v[i][0]), int(v[i][1]), T x, y;
continue; K, v[i][2]); PT() {}
3
PT(T x, T y) : x(x), y(y) {}
MO,Radovinović, Sindičić
bool operator<(const PT &rhs) pts = dn; cpx(double aa, double bb):a(aa),b (bb){}
const { return make_pair(y,x) #endif
< make_pair(rhs.y,rhs.x); } bool } double a;
operator==(const PT &rhs) // BEGIN CUT double b;
const { return make_pair(y,x) == // The following code solves SPOJ double modsq(void) const
make_pair(rhs.y,rhs.x); } {
problem #26: Build the Fence ( return a * a + b * b;
}; BSHEEP) }
T cross(PT p, PT q) { return p.x*q. y-p.y*q.x; } int main() { cpx bar(void) const
int t; {
T area2(PT a, PT b, PT c) { return cross(a,b) + scanf("%d", &t); return cpx(a, -b);
cross(b,c) + cross( c,a); } for (int caseno = 0; caseno < t; caseno++) { }
};
#ifdef REMOVE_REDUNDANT int n; cpx operator +(cpx a, cpx b)
bool between(const PT &a, const PT &b, scanf("%d", &n); {
const PT &c) { vector<PT> v(n); return cpx(a.a + b.a, a.b + b.b);
return (fabs(area2(a,b,c)) < EPS for (int i = 0; i < n; i++) scanf("%lf%lf", }
&& (a.x-b.x)*(c.x-b.x) <= 0 && (a.y-b.y)*(c.y-b.y) <= 0); &v[i].x, &v[ i].y); cpx operator *(cpx a, cpx b)
} vector<PT> h(v); {
#endif map<PT,int> index; return cpx(a.a * b.a - a.b * b.b,
void ConvexHull(vector<PT> &pts) { for (int i = n-1; i >= 0; i--) a.a * b.b + a.b * b.a);
index[v[i]] = i+1; }
sort(pts.begin(), pts.end());
pts.erase(unique(pts.begin(), pts ConvexHull(h); cpx operator /(cpx a, cpx b)
.end()), pts.end()); double len = 0; {
cpx r = a * b.bar();
vector<PT> up, dn; for (int i = 0; i < h.size(); i ++) {
for (int i = 0; i < pts.size(); i ++) { return cpx(r.a / b.modsq(), r.b / b.modsq());
double dx = h[i].x - h[(i+1)% h.size()].x; }
while (up.size() > 1 && area2(
up[up.size()-2], up.back(), pts[i]) >= double dy = h[i].y - h[(i+1)% cpx EXP(double theta)
0) up.pop_back(); h.size()].y; {
while (dn.size() > 1 && area2( len += sqrt(dx*dx+dy*dy); return cpx(cos(theta),sin(theta))
dn[dn.size()-2], dn.back(), pts[i]) <= } ;
0) dn.pop_back(); if (caseno > 0) printf("\n"); }
up.push_back(pts[i]); printf("%.2f\n", len); const double two_pi = 4 * acos(0);
dn.push_back(pts[i]); for (int i = 0; i < h.size(); i ++) { // in:input array
} // out:output array
pts = dn; if (i > 0) printf(" "); printf("%d", // step: {SET TO 1} (used
for (int i = (int) up.size() - 2; i >= 1; i--) index[h[i]]); internally)
pts.push_back(up [i]); } // size: length of the input/ output {MUST
printf("\n"); BE A POWER OF 2}
#ifdef REMOVE_REDUNDANT }
} // dir:either plus or minus one (direction of
if (pts.size() <= 2) return; the FFT)
dn.clear(); // END CUT // RESULT: out[k] = \sum_{j=0}ˆ{ size - 1}
dn.push_back(pts[0]);
dn.push_back(pts[1]); in[j] * exp(dir * 2pi * i * j * k / size)
for (int i = 2; i < pts.size(); i ++) {
3 Numerical algorithms void FFT(cpx *in, cpx *out, int step, int size, int dir)
if (between(dn[dn.size()-2], dn [dn.size()- {
3.1 Fast Fourier transform if(size < 1) return;
1], pts[i])) dn. pop_back();
if(size == 1)
dn.push_back(pts[i]); #include <cassert> {
} #include <cstdio> out[0] = in[0];
if (dn.size() >= 3 && between(dn. back(), #include <cmath> return;
dn[0], dn[1])) { struct cpx }
dn[0] = dn.back(); {
dn.pop_back(); cpx(){} FFT(in, out, step * 2, size / 2, dir);
} cpx(double aa):a(aa),b(0){} FFT(in + step, out + size / 2,
4
MO,Radovinović, Sindičić
step * 2, size / 2, dir); for(int i = 0 ; i < 8 ; i++) while (b) { int t = a%b; a = b; b
for(int i = 0 ; i < size / 2 ; i ++) { = t; }
cpx Ai(0,0); return a;
{ for(int j = 0 ; j < 8 ; j++) }
cpx even = out[i]; { // computes lcm(a,b)
cpx odd = out[i + size / 2]; out[i] = even +
Ai = Ai + a[j] * EXP(j * i * two_pi / 8); int lcm(int a, int b) {
EXP(dir * return a / gcd(a, b)*b;
two_pi * i / size) * odd; } }
printf("%7.2lf%7.2lf", Ai.a, Ai
out[i + size / 2] = even + EXP( dir * two_pi * (i + size / .b); // (aˆb) mod m via successive
2) / size) * odd; } squaring
} printf("\n"); int powermod(int a, int b, int m) { int ret = 1;
} cpx AB[8]; while (b) {
// Usage: for(int i = 0 ; i < 8 ; i++) if (b & 1) ret = mod(ret*a, m);
// f[0...N-1] and g[0..N-1] are numbers AB[i] = A[i] * B[i];
cpx aconvb[8]; a = mod(a*a, m); b >>= 1;
// Want to compute the convolution h, FFT(AB, aconvb, 1, 8, -1); for(int i = 0 ; i < }
defined by 8 ; i++) aconvb[i] = aconvb[i] / 8; for(int i = return ret;
// h[n] = sum of f[k]g[n-k] (k = 0, }
..., N-1). 0 ; i < 8 ; i++) // returns g = gcd(a, b); finds x, y such that
// Here, the index is cyclic; f[-1] {
= f[N-1], f[-2] = f[N-2], etc. printf("%7.2lf%7.2lf", aconvb[i g = ax + by
// Let F[0...N-1] be FFT(f), and similarly, ].a, aconvb[i].b); int extended_euclid(int a, int b, int &x, int
define G and H. } &y) {
printf("\n"); int xx = y = 0;
// The convolution theorem says H[n ] = int yy = x = 1;
for(int i = 0 ; i < 8 ; i++)
F[n]G[n] (element-wise product). { while (b) {
// To compute h[] in O(N log N) time, do cpx aconvbi(0,0); int q = a / b;
the following: for(int j = 0 ; j < 8 ; j++) int t = b; b = a%b; a = t;
// 1. Compute F and G (pass dir = { t = xx; xx = x - q*xx; x = t; t = yy; yy = y - q*yy; y = t;
1 as the argument). aconvbi = aconvbi + a[j] * b [(8 + i - j) % 8]; }
// 2. Get H by element-wise return a;
multiplying F and G. } }
// 3. Get h by taking the inverse printf("%7.2lf%7.2lf", aconvbi.
FFT (use dir = -1 as the a, aconvbi.b); // finds all solutions to ax = b ( mod n)
argument) }
printf("\n"); vi modular_linear_equation_solver( int a, int
// and *dividing by N*. DO NOT FORGET THIS b, int n) {
SCALING FACTOR. return 0; int x, y;
int main(void) } vi ret;
{ int g = extended_euclid(a, n, x, y);
printf("If rows come in identical pairs, then
everything works if (!(b%g)) {
.\n"); 3.2 Euclid and Fermat's Theorem x = mod(x*(b / g), n);
cpx a[8] = {0, 1, cpx(1,3), cpx (0,5), 1, 0, // This is a collection of useful code for for (int i = 0; i < g; i++) ret.push_back(mod(x + i*(n /
2, 0}; solving problems that
cpx b[8] = {1, cpx(0,-2), cpx (0,1), 3, -1, - g), n));
3, 1, -2}; // involve modular linear equations }
cpx A[8]; . Note that all of the return ret;
cpx B[8]; // algorithms described here work }
FFT(a, A, 1, 8, 1); FFT(b, on nonnegative integers. // computes b such that ab = 1 (mod n), returns
B, 1, 8, 1); #include "template.h" -1 on failure
for(int i = 0 ; i < 8 ; i++) // return a % b (positive value) int int mod_inverse(int a, int n) { int x, y;
{ mod(int a, int b) {
printf("%7.2lf%7.2lf", A[i].a, return ((a%b) + b) % b; int g = extended_euclid(a, n, x, y);
A[i].b); }
} // computes gcd(a,b) if (g > 1) return -1;
printf("\n"); int gcd(int a, int b) { return mod(x, n);
5
MO,Radovinović, Sindičić
} return true; vector primeNum contains all the prime
// Chinese remainder theorem ( special } numbers
case): find z such that int g = gcd(a, b); */
// z % m1 = r1, z % m2 = r2. Here, if (c % g) return false; vi primeNum;
x = c / g * mod_inverse(a / g, b
z is unique modulo M = lcm(m1, m2). / g); int isPrime[Lim];
y = (c - a*x) / b; void pop_isPrime(int limit) {
// Return (z, M). On failure, M = -1. return true; mem(isPrime, 0);
pii chinese_remainder_theorem(int m1, int } rep1(i, 2, limit) {
r1, int m2, int r2) { int main() { if (isPrime[i])
int s, t; // expected: 2 continue;
int g = extended_euclid(m1, m2, s cout << gcd(14, 30) << endl;
, t); if (i <= (int)(sqrt(limit)+10)) for(ll j = i*i; j <= limit; j
// expected: 2 -2 1 int
if (r1%g != r2%g) return x, y; += i)
make_pair(0, -1); int g = extended_euclid(14, 30, x isPrime[j] = i;
return make_pair(mod(s*r2*m1 + t* r1*m2, m1*m2) / g, m1*m2 / , y);
g); primeNum.pb(i);
cout << g << " " << x << " " << y isPrime[i]=i;
} << endl; }
// Chinese remainder theorem: find z such // expected: 95 45 vi }
that sols =
// z % m[i] = r[i] for all i. Note that the solution is
int main() {
modular_linear_equation_solver (14, 30, fast;
// unique modulo M = lcm_i (m[i]). Return (z, 100); pop_isPrime(500);
M). On for (int i = 0; i < sols.size(); i++) cout << rep1(i, 1, 500)
// failure, M = -1. Note that we do not require sols[i] << " "; cout << i << ’ ’ << isPrime[i]
the a[i]’s cout << endl; << ’\n’;
// to be relatively prime. // expected: 8 }
pii chinese_remainder_theorem(const cout << mod_inverse(8, 9) << endl
vi &m, const vi &r) { ;
pii ret = make_pair(r[0], m[0]); // expected: 23 105 3.4 Fast exponentiation
for (int i = 1; i < m.size(); i ++) { // 11 12 /
int v1[3]={3,5,7}, v2[3]={2,3,2}; pii ret = *
ret = chinese_remainder_theorem Uses powers of two to exponentiate numbers
(ret.second, ret.first, m[i ], r[i]); chinese_remainder_theorem(vi( v1, and matrices. Calculates
v1+3), vi(v2, v2+3)); nˆk in O(log(k)) time when n is a number. If A is
if (ret.second == -1) break; cout << ret.first << " " << ret.
} second << endl; an n x n matrix,
return ret; int v3[2]={4,6}, v4[2]={3,5}; ret = calculates Aˆk in O(nˆ3*log(k))
} chinese_remainder_theorem( time.
/
// computes x and y such that ax + by = c vi(v3, v3+2), vi(v4, v4+2)); cout << *
ret.first << " " << ret. #include <iostream>
// returns whether the solution second << endl; #include <vector>
exists // expected: 5 -15 using namespace std;
bool linear_diophantine(int a, int b, int c, int if (!linear_diophantine(7, 2, 5, typedef double T; typedef
&x, int &y) { x, y)) cout << "ERROR" << endl
vector<T> VT; typedef
if (!a && !b) { ;
cout << x << " " << y << endl; return 0; vector<VT> VVT;
if (c) return false; x = 0; y
= 0; return true; T power(T x, int k) {
} T ret = 1;
}
if (!a) { while(k) {
if(k & 1) ret *= x;
if (c % b) return false; x = 0; y
3.3 Sieve for Prime Numbers k >>= 1; x *= x;
= c / b; return true; }
} #include "template.h" return ret;
if (!b) { /*
}
if (c % a) return false; x = c / a; y isPrime stores the largest prime number VVT multiply(VVT& A, VVT& B) {
= 0; which divides the index int n = A.size(), m = A[0].size()
6
MO,Radovinović, Sindičić
, k = B[0].size(); VVT }
C(n, VT(k, 0)); }
for(int i = 0; i < n; i++) 4 Graph algorithms }
for(int j = 0; j < k; j++) 4.1 Fast Dijkstra's algorithm printf("%d\n", dist[t]); if (dist[t] <
for(int l = 0; l < m; l++) INF)
// Implementation of Dijkstra’s algorithm for (int i = t; i != -1; i = dad[i])
C[i][j] += A[i][l] * B[l][j ];
using adjacency lists printf("%d%c", i, (i == s ? ’ \n’ : ’ ’));
return C; // and priority queue for
} efficiency. return 0;
VVT power(VVT& A, int k) { // }
int n = A.size(); // Running time: O(|E| log |V|) /*
VVT ret(n, VT(n)), B = A; Sample input:
#include "template.h" const int INF
for(int i = 0; i < n; i++) ret[i ][i]=1; = 2000000000;
50 4
21 2 3 1
while(k) { int main() { 22 4 4 5
31 4 3 3 41
if(k & 1) ret = multiply(ret, B ); int N, s, t; 20 1 2 3
scanf("%d%d%d", &N, &s, &t); 21 5 2 1
k >>= 1; B = multiply(B, B); vector<vector<pii> > edges(N); for (int i
} Expected:
return ret; = 0; i < N; i++) { 5
} int M; 42 3 0
scanf("%d", &M);
int main() for (int j = 0; j < M; j++) { int vertex, /
{ *
dist;
/* Expected Output: scanf("%d%d", &vertex, &dist)
2.37ˆ48 = 9.72569e+17 ; 4.2 Topological sort (C++)
376 264 285 220 265 edges[i].push_back(make_pair(
550 376 529 285 484
dist, vertex)); // note order of
arguments here // This function uses performs a non-recursive
484 265 376 264 285 } topological sort.
285 220 265 156 264 } //
529 285 484 265 376 */ double n = // Running time: O(|V|ˆ2). If you use
2.37; // use priority queue in which top element
int k = 48; has the "smallest" adjacency lists (vector<map<
priority int> >),
cout << n << "ˆ" << k << " = " << power(n, k) // the running time
<< endl; priority_queue<pii, vector<pii>,
greater<pii> > Q; is reduced to O(|E|).
double At[5][5] = { //
vector<int> dist(N, INF), dad(N, -1);
{ 0, 0, 1, 0, 0 }, { 1, 0, 0, 1, // INPUT: w[i][j] = 1 if i should come
0 }, { 0, 0, 0, 0, 1 }, { 1, 0, Q.push(make_pair(0, s)); dist[s] before j, 0 otherwise
= 0;
0, 0, 0 }, { 0, 1, 0, 0, 0 } }; while (!Q.empty()) { // OUTPUT: a permutation of
pii p = Q.top(); 0,...,n-1 (stored in a vector)
vector <vector <double> > A(5, vector Q.pop(); // which represents an
<double>(5)); int here = p.second; ordering of the nodes which
for(int i = 0; i < 5; i++) if (here == t) break; // is consistent with w
for(int j = 0; j < 5; j++) if (dist[here] != p.first) //
A[i][j] = At[i][j]; continue; // If no ordering is possible, false is
vector <vector <double> > Ap = returned.
for (vector<pii>::iterator it =
power(A, k); edges[here].begin(); it != // TODO Optimization required
cout << endl; edges[here].end(); it++) { #include <iostream>
for(int i = 0; i < 5; i++) { for(int j = 0; j if (dist[here] + it->first < #include <queue>
dist[it->second]) { dist[it- #include <cmath>
< 5; j++) cout << Ap[i][j] << " "; >second] = dist[ #include <vector>
cout << endl; here] + it->first; using namespace std;
} dad[it->second] = here;
} Q.push(make_pair(dist[it-> typedef double T;
second], it->second)); typedef vector<T> VT;
7
MO,Radovinović, Sindičić
typedef vector<VT> VVT; // false if a negative weight cycle is detected.
typedef vector<int> VI; 4.4 Strongly connected components Otherwise, the
typedef vector<VI> VVI; // function returns true and dist[i ] is the length
#include "template.h" #define of the shortest
bool TopologicalSort (const VVI &w, VI // path from start to i.
&order){ MAXE 1000000 #define MAXV //
int n = w.size(); 100000 struct edge{int e, nxt;}; // Running time: O(|V|ˆ3)
VI parents (n); int V, E; //
queue<int> q; edge e[MAXE], er[MAXE]; int // INPUT: start, w[i][j] = cost of edge from i
order.clear(); sp[MAXV], spr[MAXV]; to j
for (int i = 0; i < n; i++){ for (int j = 0; j int group_cnt, group_num[MAXV]; bool // OUTPUT: dist[i] = min weight
< n; j++) v[MAXV]; path from start to i
if (w[j][i]) parents[i]++; int stk[MAXV]; // Stack, stk[0] // prev[i] = previous
if (parents[i] == 0) q.push ( stores size node on the best path from the
i); void fill_forward(int x) { int i; // start node
} #include <iostream>
v[x]=true;
while (q.size() > 0){ for(i=sp[x];i;i=e[i].nxt) if(!v[e [i].e]) #include <queue>
int i = q.front(); fill_forward(e[i].e); #include <cmath>
q.pop(); stk[++stk[0]]=x; #include <vector>
order.push_back (i); } using namespace std;
for (int j = 0; j < n; j++) if (w[i][j]){ void fill_backward(int x) { int i; typedef double T; typedef
parents[j]--; vector<T> VT; typedef
v[x]=false; vector<VT> VVT;
if (parents[j] == 0) q.push ( j); group_num[x]=group_cnt;
for(i=spr[x];i;i=er[i].nxt) if(v[ er[i].e]) typedef vector<int> VI;
} typedef vector<VI> VVI;
} fill_backward(er[i]. e);
bool BellmanFord (const VVT &w, VT
return (order.size() == n); } &dist, VI &prev, int start){
} void add_edge(int v1, int v2) { int n = w.size();
//add edge v1->v2 prev = VI(n, -1);
e [++E].e=v2; e [E].nxt=sp [v1]; sp [v1]=E; dist = VT(n, 1000000000);
dist[start] = 0;
4.3 Union- nd set(aka DSU) er[ E].e=v1; er[E].nxt=spr[v2]; spr[v2]=E; for (int k = 0; k < n; k++){ for (int i = 0; i
} < n; i++){
#include "template.h" for (int j = 0; j < n; j++){ if (dist[j] >
void SCC() { dist[i] + w[i
int find(vector<int> &C, int x) { return (C[x] int i; ][j]){
== x) ? x : C[x] = find(C, C[x]); } stk[0]=0; if (k == n-1) return
memset(v, false, sizeof(v)); false;
void merge(vector<int> &C, int x, int y) { for(i=1;i<=V;i++) if(!v[i]) dist[j] = dist[i] + w[i][ j];
fill_forward(i);
C[find(C, x)] = find(C, y); } group_cnt=0; prev[j] = i;
int main() { for(i=stk[0];i>=1;i--) if(v[stk[i }
]]){group_cnt++; fill_backward (stk[i]);} }
int n = 5; }
vector<int> C(n); } }
for (int i = 0; i < n; i++) C[i]
= i; int main() {return 0;} return true;
merge(C, 0, 2); }
merge(C, 1, 0);
merge(C, 3, 4); 4.5 Bellman Ford's algorithm
for (int i = 0; i < n; i++) cout << i << " " << 4.6 Minimum Spanning Tree: Kruskal
find(C, i) << endl; // This function runs the Bellman-Ford /
algorithm for single source *
return 0; // shortest paths with negative edge
} Uses Kruskal’s Algorithm to calculate
weights. The function returns the weight of the minimum spanning
8
MO,Radovinović, Sindičić
forest (union of minimum spanning trees of if(R[uc] > R[vc])
each connected component) of C[vc] = uc; int main() {
else if(R[vc] > R[uc]) int total=0, start_vertex = 0; rep(i,
a possibly disjoint graph, given in the form of a C[uc] = vc; max_vertices)
else if(adj[i].size()&1)
matrix of edge weights C[vc] = uc; R[uc]++; // if the
(-1 if no edge exists). Returns the weight of the }
} size is odd then increment ’ total’
minimum spanning return weight;
forest (also calculates the actual } total++, start_vertex=i; // put the
edges - stored in T). Note: uses a int main() { starting vertex as an odd degree
disjoint-set data structure with amortized int n; vertex
(effectively) constant time per cin >> n; if(total==0||total==2) {
vii Alist[Lim]; // necessary
cout << Kruskal(Alist, n) << endl
; and sufficient condition to check the
union/find. Runs in O(E*log(E)) time. existence of an EC
*/
}
find_path(start_vertex); rep(i,
#include "template.h" path.size()) cout <<
typedef int T; path[i] << " ";
struct edge{
4.7 Eulerian Path Algo }
int u, v; else
#include "template.h" cout << "No Eulerian Circuit\n"
T d; ;
}; struct Edge; return 0;
struct edgeCmp{ typedef list<Edge>::iterator iter; }
int operator()(const edge& a, const struct Edge {
edge& b) { return a.d > b.d; } int next_vertex;
iter reverse_edge; 4.8 FloydWarshall's Algorithm
};
Edge(int next_vertex) :
int find(vector <int>& C, int x) { return (C[x] next_vertex(next_vertex) #include "template.h"
== x)?x: C[x]=find( C, C[x]); } {} typedef double T; typedef
}; vector<T> vt; typedef
T Kruskal(vii Alist[], int n){ T weight = 0; const int max_vertices = 10; vector<vt> vvt; typedef
// int num_vertices = 6; vector<vi> vvi;
vector <int> C(n), R(n); list<Edge> adj[max_vertices]; // // This function runs the Floyd-Warshall
for(int i=0; i<n; i++) { C[i] = i adjacency list algorithm for all-pairs
; R[i] = 0; } vector<int> path; // shortest paths. Also handles negative
vector <edge> T; void find_path(int v) { edge weights. Returns true
priority_queue <edge, vector < edge>, while(adj[v].size() > 0) { // if a negative weight cycle is
edgeCmp> E; int vn = adj[v].front(). found.
rep(i, n) next_vertex; //
rep(j, Alist[i].size()) { edge e; adj[vn].erase(adj[v].front(). // Running time: O(|V|ˆ3)
reverse_edge); //
e.u = i, e.v = Alist[i][j].F, adj[v].pop_front(); // INPUT: Alist[i][j] = Alisteight of edge
e.d = Alist[i][j].S; find_path(vn); from i to j
E.push(e); }
path.push_back(v); // OUTPUT: Alist[i][j] = shortest path from i
} to j
}
while(T.size() < n-1 && !E.empty // prev[i][j] = node
()) { void add_edge(int a, int b) { before j on the best path starting
edge cur = E.top(); E.pop(); int uc = adj[a].push_front(Edge(b)); iter ita = at i
find(C, cur.u), vc = adj[a].begin(); bool FloydWarshall (vvt &Alist, vvi &prev) {
find(C, cur.v); adj[b].push_front(Edge(a)); iter itb =
if(uc != vc) { int n = Alist.size(); prev = vvi(n,
adj[b].begin(); ita->reverse_edge =
T.push_back(cur); weight += cur.d; itb; itb->reverse_edge = ita; vi(n, -1));
} for (int k = 0; k < n; k++){
9
MO,Radovinović, Sindičić
FER,PMF-
for (int i = 0; i < n; i++){ for (int j = 0; j < int best = -1; // reached and thus the base of the blossom
n; j++){ for (int k = 0; k < n; k++) if (!found[k]){ is an unmatched node.
if (Alist[i][j] > Alist[i][ k] + Alist[k][j]){ // blossom should be empty when dfs is
if (w[here][k] != -1 && dist[ k] > called and
Alist[i][j] = Alist[i][k] w[here][k]){ // contains the nodes of the
+ Alist[k][j]; dist[k] = w[here][k]; blossom when a blossom is found.
prev[i][j] = k; prev[k] = here; bool dfs(int n, vvi &conn, vi &
} } blossom) {
} if (best == -1 || dist[k] < vis[n]=0;
} dist[best]) best = k; rep(i, N) {
} } if(conn[n][i]) {
here = best; if(vis[i]==-1) {
// check for negative weight cycles } vis[i]=1;
for(int i=0;i<n;i++) T tot_weight = 0; if(match[i]==-1 || dfs( match[i], conn,
if (Alist[i][i] < 0) return for (int i = 0; i < n; i++) if ( prev[i] != -1){ blossom)
false; ) { couple(n,i); return true; }
return true; edges.push_back (make_pair (
} prev[i], i)); }
tot_weight += w[prev[i]][i]; if(vis[i]==0 || SZ(blossom))
} { // found flower blossom.pb(i);
2 return tot_weight; blossom.pb(n
4.9 Prim's Algo in O(n ) time } ); if(n==blossom[0]) { match[n
#include "template.h" ]=-1; return true; } return
false;
// This function runs Prim’s algorithm 4.10 MST for a directed graph }
for constructing minimum }
/* Edmond’s Algorithm for finding an }
// weight spanning trees. aborescence return false;
// }
// Running time: O(|V|ˆ2) * Produces an aborescence ( directed analog of a // search for an augmenting path.
// minimum // if a blossom is found build a new graph
// INPUT: w[i][j] = cost of edge (newconn) where the
from i to j * spaning tree) of least weight in O(m*n) time // (free) blossom is shrunken to a single
// / node and recurse.
*
// NOTE: Make sure that w[i][j] is #include "template.h" // if a augmenting path is found it has already
nonnegative and #define sz size() been augmented
// symmetric. Missing edges // except if the augmented path ended on
should be given -1 weight. #define D(x) if(1) cout << __LINE__ ;<<" "<< #x " = the shrunken blossom.
// " << (x) << endl // in this case the matching should be
// OUTPUT: edges = list of pair< #define D2(x,y) if(1) cout << updated along the
int,int> in minimum __LINE__ <<" "<< #x " = " << (x) appropriate
// spanning tree return \ // direction of the blossom. bool
<<", " << #y " = " << (y) << endl
total weight of tree ; augment(vvi &conn) {
typedef double T; typedef typedef vector<vi> vvi; #define rep(m, N) { if(match[m]==-
vector<T> vt; typedef 1) {
SZ(x) ((x).size()) int N; vi blossom; vis=vi(N,-1);
vector<vt> vvt; typedef
vector<vi> vvi; vi match; if(!dfs(m, conn, blossom))
T Prim (const vvt &w, vii &edges){ int n = vi vis; continue; if(SZ(blossom)==0)
w.size(); void couple(int n, int m) { match[n ]=m; return
vi found (n); match[m]=n; } true; // augmenting path found
vi prev (n, -1);
vt dist (n, 1000000000); int here // returns true if something interesting has // blossom is found so build
= 0; dist[here] = 0; been found, thus a shrunken graph
// augmenting path or a blossom (if blossom int base=blossom[0], S=SZ(
while (here != -1){ is non-empty). blossom);
10
found[here] = true; // the dfs returns true from the moment the vvi newconn=conn;
stem of the flower is
MO,Radovinović, Sindičić
FER,PMF-
rep1(i, 1, S-1) rep(j, N) newconn[base][j]=newconn[j
if (u2 < 0 || !vis[u2] && dist[
4.11 Maximum Matching in a Bipartite u2] == dist[u1] + 1 && dfs(
][base]|=conn[blossom[i]][ j]; u2)) {
graphss matching[v] = u1;
rep1(i, 1, S-1) rep(j, N) used[u1] = true;
newconn[blossom[i]][j]= // Hopcraft-Karp Algo for finding Maximum return true;
Biparitie }
newconn[j][blossom[i]]=0; // Matching using Augmenting paths }
newconn[base][base]=0; // is now the return false;
new graph #include "template.h" }
if(!augment(newconn)) return false; const int MAXN1 = 50000; int maxMatching() {
int n=match[base]; const int MAXN2 = 50000; fill(used, used + n1, false);
D(base); const int MAXM = 150000; fill(matching, matching + n2, -1)
// if n!=-1 the augmenting path ended int n1, n2, edges, last[MAXN1], ;
for (int res = 0;;) {
on this blossom prev[MAXM], head[MAXM]; bfs();
if(n!=-1) rep(i, S) if(conn[ int matching[MAXN2], dist[MAXN1], Q fill(vis, vis + n1, false); int f = 0;
blossom[i]][n]) { [MAXN1];
couple(blossom[i], n); bool used[MAXN1], vis[MAXN1]; for (int u = 0; u < n1; ++u)
if(i&1) for(int j=i+1; j<S; j+=2) void init(int _n1, int _n2) { n1 = _n1; if (!used[u] && dfs(u))
couple(blossom[j ++f;
n2 = _n2; if (!f)
],blossom[j+1]); else for(int return res;
j=0; j<i; j edges = 0; res += f;
+=2) couple(blossom[j], fill(last, last + n1, -1); }
blossom[j+1]); } }
break; void addEdge(int u, int v) {
} int main() {
head[edges] = v; init(2, 2);
return true; prev[edges] = last[u];
} addEdge(0, 0); addEdge(0, 1);
} last[u] = edges++; addEdge(1, 1);
return false; }
cout << (2 == maxMatching()) << endl;
} void bfs() {
int edmonds(vvi &conn) { //conn is the fill(dist, dist + n1, -1); int sizeQ = }
0;
Adjacency matrix for (int u = 0; u < n1; ++u) { if (!used[u]) {
int res=0; Q[sizeQ++] = u; 4.12 Articulation Pt/Bridge in a Graph
match=vi(N,-1); dist[u] = 0;
while(augment(conn)) res++; } #include "template.h"
return res; }
} // Array u acts as visited bool array, d
for (int i = 0; i < sizeQ; i++) { int u1 = Q[i]; stores DFN No., low
int main() { // stores lowest DFN no reachable, par stores
vvi conn(10, vi(10, 0)); // Adjacency for (int e = last[u1]; e >= 0; e = prev[e]) { parent node’s DFN no.
matrix int u2 = matching[head[e]]; int gl = 0;
#define addEdge(x,y) conn[x][y]= if (u2 >= 0 && dist[u2] < 0) const int N = 10010;
conn[y][x] = 1; { int u[N],d[N],low[N],par[N]; vi G[N];
dist[u2] = dist[u1] + 1; Q[sizeQ++]
addEdge(1,2); = u2;
addEdge(2,3); void dfs1(int node,int dep){ //find dfs_num and
} dfs_low
addEdge(2,5); } u[node]=1;
addEdge(5,3); } d[node]=dep;low[node]=dep;
addEdge(3,4); } for(int i = 0; i < G[node].size()
addEdge(5,6); ; i++){
N = conn.size(); bool dfs(int u1) {
D(edmonds(conn)); vis[u1] = true; int it = G[node][i];
return 0; for (int e = last[u1]; e >= 0; e if(!u[it]){
} = prev[e]) { par[it]=node;
int v = head[e]; dfs1(it,dep+1);
11
int u2 = matching[v]; low[node]=min(low[node],low[
MO,Radovinović, Sindičić
FER,PMF-
it]); void rec (int l, int r) { if (r - l <= void update(int x , int y , int val ){
3) {
/*if(low[it] > d[node] ){ node-it is cut edge/ for (int i=l; i<=r; ++i) int y1;
bridge for (int j=i+1; j<=r; ++j) while (x <= n){
}*/ upd_ans (a[i], a[j]); sort (a+l, y1 = y;
/* while (y1 <= n){ bit[x][y1] += val; y1
a+r+1, &cmp_y); return; += (y1 & -y1
if(low[it] >= d[node] && (par [node]!=-1 } ); }
|| sz(G[node]) > 2)){ x += (x & -x);
int m = (l + r) >> 1; int midx
node is cut vertex/ = a[m].x; }
articulation point rec (l, m), rec (m+1, r); static pt }
} t[MAXN];
*/ merge (a+l, a+m+1, a+m+1, a+r+1, t,
}else if(par[node]!=it) low[ &cmp_y); 5.2 Lowest common ancestor
node]=min(low[node],low[it])
; copy (t, t+r-l+1, a+l); int tsz =
else par[node]=-1; 0; const int max_nodes, log_max_nodes; int
} for (int i=l; i<=r; ++i) if (abs (a[i].x - num_nodes, log_num_nodes, root;
} midx) <
int main(){ mindist) { vector<int> children[max_nodes];
return 0; // children[i] contains the children of
} for (int j=tsz-1; j>=0 && a[i ].y - t[j].y < node i
mindist; -- j) int A[max_nodes][log_max_nodes+1];
upd_ans (a[i], t[j]); t[tsz++] = // A[i][j] is the 2ˆj-th ancestor of
4.13 Closest Pair of points in a 2D Plane a[i]; node i, or -1 if that ancestor does not
} exist
#include "template.h" } int L[max_nodes]; // L[i] is
const int MAXN = 4; struct int main(){ the distance between node i and the root
pt { int n= 4;
int x, y, id; mindist = 1E20; //final answer is stored in // floor of the binary logarithm of n
}; mindist
// comparison on basis of x sort (a, a+n, &cmp_x); int lb(unsigned int n) { if(n==0)
coordinate rec (0, n-1);
inline bool cmp_x (const pt & a, const pt return -1;
cout<<mindist<<"\n"; int p = 0;
& b) { return 0;
return a.x < b.x || a.x == b.x && a.y < b.y; } if (n >= 1<<16) { n >>= 16; p += 16; }
} if (n >= 1<< 8) { n >>= 8; p += 8; }
// comparison on basis of y
coordinate 5 Data structures if (n >= 1<< 4) { n >>= 4; p += 4; }
inline bool cmp_y (const pt & a, 5.1 BIT for 2-D plane questions if (n >= 1<< 2) { n >>= 2; p += 2; }
const pt & b) {
return a.y < b.y; /* Bit used as 2-D structure for a handling if (n >= 1<< 1) { p +=
} update/range 1; }
// a for storing points pt return p;
a[MAXN]; }
queries in a matrix in $\logˆ2{n}$ time */
double mindist; int void DFS(int i, int l) { L[i] = l;
ansa, ansb; #include "template.h"
inline void upd_ans (const pt & a, const pt int bit[M][M], n; for(int j = 0; j < children[i].
int sum( int x, int y ){ size(); j++)
& b) { int ret = 0;
while( x > 0 ){ DFS(children[i][j], l+1);
double dist = sqrt ((a.x-b.x)*(a. x-b.x) + (a.y-b.y)*(a.y-b.y) + }
int yy = y; while( yy > 0 )
.0); ret += bit[x][yy], yy -= yy & - int LCA(int p, int q) {
if (dist < mindist) yy; // ensure node p is at least as deep as
mindist = dist, ansa = a.id, ansb = b.id; x -= (x & -x); node q
} if(L[p] < L[q])
} return ret ; swap(p, q);
12
// the basic recursive function }
MO,Radovinović, Sindičić
FER,PMF-
// "binary search" for the ancestor of node #include "template.h" update(left, a, mid, val, I1, I2),
p situated on the same level as q template<typename T> update(right, mid+1, b,
struct segTree { val, I1, I2);
for(int i = log_num_nodes; i >= 0; i--) T Tree[4*Lim];
Tree[Node]=combine(Tree[left],
Tree[right]);
if(L[p] - (1<<i) >= L[q]) T combine(int l, int r) { T ret; }
p = A[p][i]; };
ret=min(l, r); // TODO return ret;
if(p == q) int main() {return 0;}
return p; }
void buildST(int Node, int a, int b) {
// "binary search" for the LCA for(int i =
log_num_nodes; i >= if (a==b)
0; i--) Tree[Node]=0; // TODO else 5.4 Lazy Propogation for Range update and
if(A[p][i] != -1 && A[p][i] != A[ q][i]) { if (a<b) { Query
int left=Node<<1, right=(Node <<1)|1,
p = A[p][i]; q = mid=(a+b)>>1;
A[q][i]; buildST(left, a, mid); buildST(right, #include "template.h"
} mid+1, b); /*
return A[p][0]; Tree[Node]=combine(Tree[left ], A lazy tree implementation of Range
} Tree[right]); Updation & Range Query
} */
int main(int argc,char* argv[]) { // read }
num_nodes, the total void buildST(int Node, int a, int b, vi Arr) { ll Arr[Lim], Tree[4*Lim], lazy[4* Lim];
number of nodes
log_num_nodes=lb(num_nodes); if (a==b) void build_tree(int Node, int a, int b) {
Tree[Node]=Arr[a];
for(int i = 0; i < num_nodes; i ++) { else if (a<b) { // Do not forget to clear lazy Array
int p; int left=Node<<1, mid=(a+b) >>1, before calling build
// read p, the parent of node i or -1 if right=(Node<<1)|1;
if(a == b) {
node i is the root buildST(left, a, mid, Arr); Tree[Node] = Arr[a];
A[i][0] = p; buildST(right, mid+1, b, Arr); } else if (a < b) {
if(p != -1) Tree[Node]=combine(Tree[left ], int mid = (a+b)>>1, left=Node <<1,
Tree[right]); right=left|1;
children[p].push_back(i); else build_tree(left, a, mid); build_tree(right,
}
root = i; } mid+1, b);
} T query(int Node, int a, int b, int S, int Tree[Node] = Tree[left]+Tree[
E) { right];
// precompute A using dynamic }
programming if (E < a || b < S) return 0; }
for(int j = 1; j <= log_num_nodes // TODO
; j++) else if (a==b) return Tree[Node ]; void Propogate(int Node, int a, int b) {
for(int i = 0; i < num_nodes; i ++) int left=Node<<1, mid=(a+b)>>1, int left=Node<<1, right=left|1;
if(A[i][j-1] != -1) right=(Node<<1)|1;
A[i][j] = A[A[i][j-1]][j if (S <= a && b <= E) return Tree[Node]+=lazy[Node]*(b-a+1); if(a != b) {
-1]; Tree[Node]; lazy[left]+=lazy[Node];
else return combine(query(left, a, mid, S, E), lazy[right]+=lazy[Node];
A[i][j] = -1; query(right, mid +1, b, S, E)); }
lazy[Node] = 0;
// precompute L } }
DFS(root, 0); void update(int Node, int a, int b, int val, void update_tree (int Node, int start, int end, ll
return 0; int I1, int I2) { value, int a,
} if (I2 < a || b < I1) return; int b) {
if (I1 <=a && b <= I2) return int mid=(a+b)>>1, left=Node<<1,
void(Tree[Node]=val); // right=left|1;
5.3 Segment tree class for range minima TODO
int left=Node<<1, mid=(a+b)>>1, if(lazy[Node] != 0)
query Propogate(Node, a, b);
13
right=(Node<<1)|1;
MO,Radovinović, Sindičić
FER,PMF-
if(a > b || a > end || b < start) int make_dp(int n) { // N log N rep(i,n) }
{ H[i][0]=i; else
return; for(int l=0,k; (k=1<<l) < n; l ++) for(int {
} else { m += i-t[i];
if(start <= a && b <= end) { if (a != b) { i=0;i+k<n;i++) H[i][l+1] = better(H[i][l], if(i > 0) i = t[i];
H[i+k][l]); }
lazy[left] += value; } }
lazy[right] += value; int query_dp(int a, int b) { return s.length();
} int l = __lg(b-a); }
Tree[Node] += value * (b - a return better(H[a][l], H[b int main()
+ 1); -(1<<l)+1][l]); {
} else { } string a = (string) "The example above
update_tree(left, start, end, value, a, illustrates the general technique for
mid); assembling "+
update_tree(right, start, end , value, "the table with a minimum of fuss. The
mid+1, b); 6 String Manipulation principle is that of the overall
Tree[Node]=Tree[left]+Tree[ search: "+
right]; 6.1 Knuth-Morris-Pratt
} / "most of the work was already done in
* getting to the current position, so very
}
} Searches for the string w in the string s (of "+
length k). Returns the "little needs to be done in leaving it. The
ll query(int Node, int start, int end, int a, int only minor complication is that the
b) { 0-based index of the first match (k if no match "+
int mid=(a+b)>>1, left=Node<<1, is found). Algorithm "logic which is correct late in the string
right=left|1; erroneously
if(lazy[Node] != 0) runs in O(k) time. gives non-proper "+ "substrings at
Propogate(Node, a, b); */ the beginning.
#include <iostream> This necessitates some
if (a > b || a > end || b < start #include <string>
) { initialization code.";
#include <vector>
return 0; } string b = "table";
else { using namespace std;
ll Sum1, Sum2; int p = KMP(a, b);
if (start <= a && b <= end) { return typedef vector<int> VI; cout << p << ": " << a.substr(p,
Tree[Node]; void buildTable(string& w, VI& t) b.length()) << " " << b << endl;
} else { {
Sum1 = query(left, start, end t = VI(w.length()); }
, a, mid); int i = 2, j = 0;
Sum2 = query(right, start, t[0] = -1; t[1] = 0;
end, mid + 1, b); return while(i < w.length())
Sum1+Sum2;
{
6.2 Su x array
}
} if(w[i-1] == w[j]) { t[i] = j +1; i++; j++; } // Begins Suffix Arrays
}
else if(j > 0) j = t[j]; else { t[i] = implementation
0; i++; } // O(n log n) - Manber and Myers
} algorithm
5.5 Range minima query in O(1) time us-ing } // SA = The suffix array. Contains the n
lookup matrix int KMP(string& s, string& w) suffixes of txt sorted in lexicographical
{ order.
/* matrix structure for finding the range minima int m = 0, i = 0; // Each suffix is represented as a
VI t; single integer (the
in O(1) time using O(n) log(n)) space */ buildTable(w, t); SAition of txt where it starts).
#include "template.h" while(m+i < s.length()) // iSA = The inverse of the suffix array. iSA[i] =
#define better(a,b) A[a]<A[b]?(a):( { the index of the
b) if(w[i] == s[m+i]) suffix txt[i..n)
int A[100100], H[1100][1100]; //A { // in the SA array. (In other words,
is the Array and H is the lookup i++; SA[i] = k <==> iSA[ k] = i)
14
matrix if(i == w.length()) return m;
MO,Radovinović, Sindičić
FER,PMF-
// With this array, you can } while (i + h < n && j + h < n
compare two suffixes in O(1): Suffix } && txt[i+h] == txt[j+h]) h++;
txt[i..n) is smaller cnt[iSA[n - h]]++;
// than txt[j..n) if and b2h[iSA[n - h]] = true; lcp[iSA[i]] = h;
only if iSA[i] < iSA[j] const int for (int i = 0; i < n; i = nex[ i]){ if (h > 0) h--;
MAX = 1000100; char txt[MAX]; }
//input for (int j = i; j < nex[i]; ++j){ }
int iSA[MAX], SA[MAX]; //output int }
cnt[MAX]; int s = SA[j] - h; // End of longest common prefixes
int nex[MAX]; //internal bool if (s >= 0){ algorithm
bh[MAX], b2h[MAX]; int head = iSA[s]; int main() {
iSA[s] = head + cnt[head int len;
// Compares two suffixes according to their ]++; b2h[iSA[s]] = // gets(txt);
first characters true; for(int i = 0; i < 1000000; i++)
bool smaller_first_char(int a, int b){ } txt[i] = ’a’;
} txt[1000000] = ’\0’;
return txt[a] < txt[b]; for (int j = i; j < nex[i]; ++j){ len = strlen(txt);
} printf("%d",len);
void suffixSort(int n){ //sort suffixes int s = SA[j] - h; suffixSort(len);
according to if (s >= 0 && b2h[iSA[s]]){ for (int k getlcp(len);
their first characters for (int return 0;
= iSA[s]+1; ! bh[k] && b2h[k]; k++) }
i=0; i<n; ++i){ b2h[k] = false;
SA[i] = i;
} }
sort(SA, SA + n, }
} 6.3 Su x tree
smaller_first_char);
for (int i=0; i<n; ++i){ #include <stdio.h>
//{SA contains the list of suffixes sorted by SA[iSA[i]] = i; bh[i] |= b2h[ #include <string.h>
their first character} i]; #include <stdlib.h>
} #define MAX_CHAR 256
for (int i=0; i<n; ++i){ }
bh[i] = i == 0 || txt[SA[i]] != for (int i=0; i<n; ++i) struct SuffixTreeNode {
txt[SA[i-1]]; iSA[SA[i]] = i; struct SuffixTreeNode *children
b2h[i] = false; } [MAX_CHAR]; //pointer to
} // End of suffix array algorithm other node via suffix link
struct SuffixTreeNode *
for (int h = 1; h < n; h <<= 1){ //{bh[i] == // Begin of the O(n) longest common prefix suffixLink;
false if the first h characters of SA[i-1] == algorithm end) interval specifies
/*(start,
// Refer to "Linear-Time Longest- the edge, by which the
the first h characters of SA [i]} node is connected to its parent
Common-Prefix Computation in Suffix node. Each edge will
int buckets = 0; connect two nodes, one parent
// Arrays and Its Applications" by Toru
for (int i=0, j; i < n; i = j){ j = i + 1; Kasai, Gunho Lee, Hiroki and one child, and
// Arimura, Setsuo Arikawa, and Kunsoo (start, end) interval of a given
while (j < n && !bh[j]) j++; nex[i] = j; Park. edge will be stored
buckets++; int lcp[MAX]; in the child node. Lets say there
} are two nods A and B
if (buckets == n) break; // We are done! // lcp[i] = length of the longest common
connected by an edge with indices
Lucky bastards! prefix of suffix SA[i] and suffix SA[i-1] (5, 8) then this
//{suffixes are separted in buckets // lcp[0] = 0 indices (5, 8) will be stored in
containing txtings starting with the void getlcp(int n) node B. */
same h characters} { int start;
for (int i=0; i<n; ++i) int *end;
for (int i = 0; i < n; i = nex[ i]){ iSA[SA[i]] = i;
/*for leaf nodes, it stores the index of suffix for
cnt[i] = 0; lcp[0] = 0; the path from root to leaf*/
for (int j = i; j < nex[i]; ++j){ for (int i=0, h=0; i<n; ++i) { if (iSA[i] > 0) int suffixIndex;
{ };
15
iSA[SA[j]] = i; int j = SA[iSA[i]-1]; typedef struct SuffixTreeNode Node;
MO,Radovinović, Sindičić
FER,PMF-
} text[activeEdge]] ==
char text[100]; //Input string Node *root = NULL; int edgeLength(Node *n) { NULL) {
//Pointer to //Extension Rule 2 (A
root node return *(n->end) - (n->start) + 1; new leaf edge gets
/*lastNewNode will point to newly created internal } created)
node,
activeNode->children[
waiting for it’s suffix link to be set, which
int walkDown(Node *currNode){ text[activeEdge]] =
might get newNode(pos, &
/*activePoint change for walk down (APCFWD) using leafEnd);
a new suffix link (other than root) in
next extension of Skip/Count Trick (Trick 1). If activeLength /*A new leaf edge is created in above line starting
same phase. lastNewNode will be set to is greater from an existng node (the current
NULL when last activeNode), and
newly created internal node (if there is than current edge length, set next
any) got it’s internal node as if there is any internal node
suffix link reset to new internal node created activeNode and adjust activeEdge and waiting for it’s suffix
in next activeLength link get reset, point the suffix
link from that last internal
extension of same phase. */ Node *lastNewNode accordingly to represent same activePoint*/ node to current
= NULL; Node *activeNode = NULL; if (activeLength >= edgeLength( activeNode. Then set
currNode)) { lastNewNode
/*activeEdge is represeted as input string character activeEdge += edgeLength( to NULL indicating no more node waiting
currNode); for suffix link
index (not the character itself) */ activeLength -= edgeLength( reset.*/
currNode); if (lastNewNode != NULL
int activeEdge = -1; int ) {
activeLength = 0; activeNode = currNode;
return 1; lastNewNode->
// remainingSuffixCount tells how many suffixLink =
suffixes yet to }
return 0; activeNode;
// be added in tree } lastNewNode = NULL;
int remainingSuffixCount = 0; int }
leafEnd = -1; void extendSuffixTree(int pos) { }
int *rootEnd = NULL; int *splitEnd = // There is an outgoing edge
NULL; /*Extension Rule 1, this takes care of extending all starting with activeEdge
int size = -1; //Length of input string // from activeNode
leaves created so far in tree*/ leafEnd = pos; else {
Node *newNode(int start, int *end) // Get the next node at the
{ /*Increment remainingSuffixCount indicating that a end of edge
new suffix added to the list of suffixes yet starting
Node *node =(Node*) malloc( sizeof(Node)); to be // with activeEdge Node *next =
int i; activeNode
for (i = 0; i < MAX_CHAR; i++) added in tree*/ remainingSuffixCount++; ->children[text[ activeEdge]];
node->children[i] = NULL; /*set lastNewNode to NULL while starting a new
/*For root node, suffixLink will be set to NULL phase, if (walkDown(next)) {// Do
indicating there is no internal node walkdown { //Start from next
For internal nodes, suffixLink will be set to waiting for
root node (the new
by default in current extension and may it’s suffix link reset in current phase*/ activeNode)
change in lastNewNode = NULL; continue;
//Add all suffixes (yet to be added }
) one by one in tree /*Extension Rule 3 ( current
next extension*/ node->suffixLink while(remainingSuffixCount > 0)
= root; node->start = start; character being processed
{
node->end = end; if (activeLength == 0) is already on the edge)*/
/*suffixIndex will be set to -1 by default and activeEdge = pos; // if (text[next->start +
APCFALZ
actual suffix index will be set later for // There is no outgoing edge activeLength] ==
leaves starting with text[pos]) {
// activeEdge from //If a newly created node waiting for it’s
at the end of all phases*/ node-
16
activeNode
>suffixIndex = -1; return node; if (activeNode->children[
MO,Radovinović, Sindičić
FER,PMF-
//suffix link to be set, then set suffix link internal node created in last extensions //So tree will be printed in DFS manner
of same
//of that waiting node to curent active node phase which is still waiting for it ’s suffix link //Each edge along with it’s suffix index will be
printed
if(lastNewNode != reset, do it now.*/
NULL && void setSuffixIndexByDFS(Node *n, int labelHeight) {
activeNode !=
if (lastNewNode != NULL ) {
if (n == NULL) return;
root){
lastNewNode-> /*suffixLink of lastNewNode points to current newly if (n->start != -1) {//A non-root node
suffixLink =
activeNode; created internal node*/ lastNewNode-> //Print the label on edge from
lastNewNode = suffixLink = parent to current node
NULL; split;
} print(n->start, *(n->end));
} }
//APCFER3 /*Make the current newly created internal node int leaf = 1;
activeLength++; waiting int i;
/*STOP all further processing in this phase for it’s suffix link reset (which is pointing to for (i = 0; i < MAX_CHAR; i++)
root {
at present). If we come across any other if (n->children[i] != NULL)
and move on to next phase*/ break; {
} internal node
(existing or newly created) in next extension of if (leaf == 1 && n->
same start != -1)
/*We will be here when activePoint is in middle of printf(" [%d]\n", n
the edge being traversed and current phase, when a new leaf edge gets added
(i.e. when ->suffixIndex);
character Extension Rule 2 applies is any of the next
being processed is not on the edge (we fall off //Current node is not a leaf as
extension it has outgoing
the tree). In this case, we add a new internal of same phase) at that point,
node suffixLink of this node //edges from it.
and a new leaf edge going out of that new leaf = 0;
will point to that internal node.*/ lastNewNode = split; setSuffixIndexByDFS(n->
node. This
is Extension Rule 2, where a new leaf edge } children[i],
and a new /* One suffix got added in tree, decrement the labelHeight +
count of edgeLength(n->
internal node get created*/ splitEnd = (int*) children[i])
suffixes yet to be added.*/ remainingSuffixCount--; );
malloc(sizeof(int)); *splitEnd = }
next->start if (activeNode == root && }
+ activeLength - 1; activeLength > 0) {//
APCFER2C1 if (leaf == 1) { n->suffixIndex = size -
//New internal node Node *split = activeLength--;
newNode( labelHeight;
next->start, activeEdge = pos - printf(" [%d]\n", n->
splitEnd); remainingSuffixCount suffixIndex);
activeNode->children[ + 1; }
text[activeEdge]] = split; } else if (activeNode != }
root) {//APCFER2C2 activeNode
//New leaf coming out of new = activeNode
internal node ->suffixLink; void freeSuffixTreeByPostOrder(Node *n) {
split->children[text[ pos]] = } if (n == NULL)
newNode(pos, } return;
&leafEnd); } int i;
next->start += for (i = 0; i < MAX_CHAR; i++)
void print(int i, int j) { int k; {
activeLength; split-
>children[text[ if (n->children[i] != NULL)
next->start]] = next for (k=i; k<=j; k++) printf("%c", {
; text[k]); freeSuffixTreeByPostOrder
} (n->children[i]);
/*We got a new internal node here. If there is any //Print the suffix tree as well along with setting }
suffix index }
if (n->suffixIndex == -1)
17
MO,Radovinović, Sindičić
FER,PMF-
free(n->end); function
free(n); queue< int > q;
} 6.4 Aho Corasick Structure for string rep(i,NC) if( g[0][i] != -1 ) q.
/*Build the suffix tree and print the edge labels matching push( g[0][i] );
along with while( !q.empty() ) {
suffixIndex. suffixIndex for leaf edges will be #include "template.h" int r = q.front(); q.pop();
>= 0 and #define NC 26 // No of rep(i,NC) if( g[r][i] != -1 ) { int s = g[r][i];
for non-leaf edges will be -1*/ void buildSuffixTree() {
characters q.push( s );
#define NP 10005
size = strlen(text); int i; #define M 100005 int state = f[r];
#define MM 500005 // Max no of while( g[state][i] == -1 && state )
states state = f[state];
rootEnd = (int*) malloc(sizeof( int)); f[s] = g[state][i] == -1 ? 0
// b stores the strings in dictionary, g : g[state][i];
*rootEnd = - 1;
stores the trie using states, }
/*Root is a special node with start and end indices }
as -1, // a is the query string, lenb stores length // final smash int
as it has no parent from where an of strings in b state = 0;
// output stores the index of word which end rep(i,alen) {
edge comes to root*/ while( g[state][a[i]] == -1 ) { state =
root = newNode(-1, rootEnd); at the corresponding state
f[state];
activeNode = root; //First // f stores the blue edge (largest suffix of if( !state ) break;
activeNode will be root current word), pre is useless! }
for (i=0; i<size; i++) state = g[state][a[i]] == -1 ? 0 :
extendSuffixTree(i); // marked represent that this word occurs in g[state][a[i]];
int labelHeight = 0; string a if( state && output[ state ] != -1 ) marked[
setSuffixIndexByDFS(root, char a[M]; state ] ++;
labelHeight); char b[NP][105]; }
int nb, cnt[NP], lenb[NP], alen; int g[MM][NC], // counting
//Free the dynamically ng, f[MM], marked[MM rep(i,ng+1) if( i && marked[i] )
allocated memory ]; {
freeSuffixTreeByPostOrder(root) int s = i;
; int output[MM], pre[MM];
while( s != 0 ) cnt[ output[s]
} #define init(x) {rep(_i,NC)g[x][_i] ] += marked[i], s = f[s];
// driver program to test above functions = -1; f[x]=marked[x]=0; output[ x]=pre[x]=- }
1; } }
int main(int argc, char *argv[]) { void match() {
// strcpy(text, "abc"); ng = 0;
buildSuffixTree(); init( 0 ); 6.5 Tries Structure for storing strings
// strcpy(text, "xabxac#"); // part 1 - building trie rep(i,nb) {
buildSuffixTree(); #include "template.h"
// strcpy(text, "xabxa"); cnt[i] = 0; typedef struct Trie{
buildSuffixTree(); int state = 0, j = 0;
// strcpy(text, "xabxa$"); int words, prefixes; //only proper
while(g[state][b[i][j]] != -1
buildSuffixTree(); strcpy(text, && j < lenb[i]) state = g[ prefixes(words not included)
"abcabxabcd$"); state][b[i][j]], j++; while( j <
buildSuffixTree(); // bool isleaf; //for only checking words
// strcpy(text, " lenb[i] ) { not counting prefix or words
geeksforgeeks$"); g[state][ b[i][j] ] = ++ng; state = ng;
buildSuffixTree(); init( ng ); struct Trie * edges[26]; Trie(){
// strcpy(text, "THIS IS A TEST ++j; words = 0; prefixes = 0; rep(i,26)
TEXT$"); buildSuffixTree(); }
// strcpy(text, " // if( ng >= MM ) { cerr <<"i am edges[i] = NULL;
AABAACAADAABAAABAA$"); dying"<<endl; while(1);} }
buildSuffixTree(); return // suicide output[
0; state ] = i; } Trie; Trie * root;
} } void addword(Trie * node, string a)
18
// part 2 - building failure {
MO,Radovinović, Sindičić
FER,PMF-
rep(i,a.size()){ #include <ext/pb_ds/assoc_container // Ouput a specific number of
if(node->edges[a[i] - ’a’] == .hpp> digits past the decimal point,
NULL) #include <ext/pb_ds/tree_policy.hpp // in this case 5
node->edges[a[i] - ’a’] = new Trie(); > cout.setf(ios::fixed); cout <<
using namespace __gnu_pbds; setprecision(5);
node = node->edges[a[i] - ’a’]; node- using namespace std; cout << 100.0/7.0 << endl;
>prefixes++; template <typename T> cout.unsetf(ios::fixed);
} using ordered_set = tree<T, // Output the decimal point and
// node->isleaf = true; node- null_type, less<T>, rb_tree_tag,
trailing zeros
>prefixes--; node->words++; tree_order_statistics_node_update cout.setf(ios::showpoint);
} >; cout << 100.0 << endl;
const long long Mod = 1e9 + 7; cout.unsetf(ios::showpoint);
int count_words(Trie * node, string a){ const long long Inf = 1e18; // Output a ’+’ before positive
rep(i,a.size()){ const long long Lim = 1e5 + 1e3;
values
if(node->edges[a[i] - ’a’] == const double eps = 1e-10; cout.setf(ios::showpos);
NULL) typedef long long ll; cout << 100 << " " << -100 <<
return 0; typedef vector <int> vi; endl;
node = node->edges[a[i] - ’a’]; typedef vector <vi> vvi; cout.unsetf(ios::showpos);
} typedef vector <ll> vl;
return node->words; typedef pair <int, int> pii; // Output numerical values in
} hexadecimal
typedef pair <ll, ll> pll; cout << hex << 100 << " " << 1000
int count_prefixes(Trie * node, string a){ #define F first << " " << 10000 << dec <<
#define S second endl;
rep(i,a.size()){ #define mp make_pair }
if(node->edges[a[i] - ’a’] == #define pb push_back
NULL)
return 0; #define pi 2*acos(0.0)
node = node->edges[a[i] - ’a’]; #define rep2(i,b,a) for(ll i = (ll) 7.3 Longest increasing subsequence
} b, _a = (ll)a; i >= _a; i--)
return node->prefixes; #define rep1(i,a,b) for(ll i = (ll) // Given a list of numbers of
} a, _b = (ll)b; i <= _b; i++) length n, this routine extracts
#define rep(i,n) for(ll i = 0, _n = a
// bool find(Trie * node, string a) (ll)n ; i < _n ; i++) // longest increasing subsequence.
{ #define mem(a,val) memset(a,val, //
// rep(i,a.size()){ sizeof(a)) // Running time: O(n log n)
// if(node->edges[a[i] - ’a’] == NULL) #define all(v) v.begin(), v.end() //
#define fast ios_base:: // INPUT: a vector of integers
// return false; sync_with_stdio(false),cin.tie // OUTPUT: a vector containing
// node = node->edges[a[i] - ’a ’]; (0),cout.tie(0); the longest increasing
// } int main () { subsequence
// return node->isleaf; ordered_set<int> X; #include <iostream>
// } X.insert(1); X.insert(2); X. #include <vector>
int main(){ insert(4); X.insert(8); X. #include <algorithm>
root = new Trie(); insert(16);
cout << *X.find_by_order(5) <<
using namespace std;
rep(i,26) ’\n’; typedef vector<int> VI;
if(root->edges[i] != NULL) cout << X.order_of_key(4) << ’\ typedef pair<int,int> PII;
cout<<(char)(’a’ + i); return 0; n’; typedef vector<PII> VPII;
return 0;
} } #define STRICTLY_INCREASNG
VI LongestIncreasingSubsequence(VI
v) {
7 Miscellaneous VPII best;
7.2 C++ input/output VI dad(v.size(), -1);
7.1 C++ template for (int i = 0; i < v.size(); i
#include "template.h" ++) {
19
#include <bits/stdc++.h>
int main() { #ifdef STRICTLY_INCREASNG
MO,Radovinović, Sindičić
FER,PMF-
PII item = make_pair(v[i], 0); VPII::iterator { ], dp[i][j-1]);
it = lower_bound (best.begin(), if(!i || !j) return; }
best.end(), if(A[i-1] == B[j-1]) { res. VT res;
item); push_back(A[i-1]); backtrack( backtrack(dp, res, A, B, n, m);
item.second = i; dp, res, A, B, i-1, j-1); } reverse(res.begin(), res.end()); return res;
#else else
PII item = make_pair(v[i], i); VPII::iterator { }
it = upper_bound (best.begin(), if(dp[i][j-1] >= dp[i-1][j]) backtrack(dp, set<VT> LCSall(VT& A, VT& B)
best.end(), {
item); res, A, B, i, j-1);
VVI dp;
#endif else backtrack(dp, res, A, B, i -1, j); int n = A.size(), m = B.size();
if (it == best.end()) { dp.resize(n+1);
dad[i] = (best.size() == 0 ? }
-1 : best.back().second); for(int i=0; i<=n; i++) dp[i].
} resize(m+1, 0);
best.push_back(item);
} else { void backtrackall(VVI& dp, set<VT>& res, VT& for(int i=1; i<=n; i++)
dad[i] = dad[it->second]; A, VT& B, int i, int j for(int j=1; j<=m; j++)
*it = item; ) {
} { if(A[i-1] == B[j-1]) dp[i][j]
} if(!i || !j) { res.insert(VI()); return; } = dp[i-1][j-1]+1;
VI ret; else dp[i][j] = max(dp[i-1][j ], dp[i][j-1]);
for (int i = best.back().second; i >= 0; i = if(A[i-1] == B[j-1])
{ }
dad[i]) set<VT> tempres; set<VT> res;
ret.push_back(v[i]); backtrackall(dp, res, A, B, n, m)
reverse(ret.begin(), ret.end()); return ret; backtrackall(dp, tempres, A, B, i-1, j-1); ;
return res;
} for(set<VT>::iterator it= tempres.begin(); }
it!=tempres
.end(); it++) int main()
{ {
7.4 Longest common subsequence VT temp = *it;
int a[] = { 0, 5, 5, 2, 1, 4, 2, 3 }, b[] = { 5, 2, 4,
temp.push_back(A[i-1]); 3, 2, 1,
/* 2, 1, 3 };
res.insert(temp); VI A = VI(a, a+8), B = VI(b, b+9)
Calculates the length of the longest } ;
common subsequence of two vectors. } VI C = LCS(A, B);
else
Backtracks to find a single subsequence or all { for(int i=0; i<C.size(); i++)
cout << C[i] << " ";
subsequences. Runs in if(dp[i][j-1] >= dp[i-1][j]) backtrackall(dp, cout << endl << endl;
O(m*n) time except for finding all res, A, B, i, j-1); set <VI> D = LCSall(A, B);
longest common subsequences, if(dp[i][j-1] <= dp[i-1][j]) backtrackall(dp, for(set<VI>::iterator it = D.
which begin(); it != D.end(); it++)
may be slow depending on how many there res, A, B, i-1, j); {
are. }
/ for(int i=0; i<(*it).size(); i ++) cout << (*it)[i] << " ";
* }
#include <iostream> VT LCS(VT& A, VT& B) cout << endl;
#include <vector> { }
#include <set> VVI dp; }
#include <algorithm> int n = A.size(), m = B.size();
using namespace std; dp.resize(n+1);
typedef int T; typedef for(int i=0; i<=n; i++) dp[i]. 7.5 Gauss Jordan
vector<T> VT; typedef resize(m+1, 0);
// Gauss-Jordan elimination with full
vector<VT> VVT; for(int i=1; i<=n; i++) pivoting.
typedef vector<int> VI; for(int j=1; j<=m; j++) //
{ // Uses:
typedef vector<VI> VVI; if(A[i-1] == B[j-1]) dp[i][j] // (1) solving systems of linear equations
void backtrack(VVI& dp, VT& res, VT & A, = dp[i-1][j-1]+1; (AX=B)
20
VT& B, int i, int j) else dp[i][j] = max(dp[i-1][j // (2) inverting matrices (AX=I)
MO,Radovinović, Sindičić
FER,PMF-
// (3) computing determinants of for (int q = 0; q < m; q++) b if(x1==1 && x0!=1 && x0!=n-1)
square matrices [p][q] -= b[pk][q] * c; return true;
// } x0=x1;
// Running time: O(nˆ3) } }
for (int p = n-1; p >= 0; p--) if (irow[p] != if(x0!=1) return true;
// return false;
// INPUT:a[][] = an nxn matrix icol[p]) {
}
// b[][] = an nxm matrix for (int k = 0; k < n; k++)
// swap(a[k][irow[p]], a[k][ icol[p]]); ll Random(ll n) {
// OUTPUT: X = an nxm matrix ll ret=rand(); ret*=32768; ret+=rand();
}
(stored in b[][]) ret*=32768; ret+=rand(); ret*=32768;
// Aˆ{-1} = an nxn matrix (stored return det; ret+=rand();
in a[][]) } return ret%n;
// returns determinant of int main() { }
a[][] vvt a(100), b(100); bool IsPrimeFast(ll n, int TRIAL) {
#include "template.h" double det = GaussJordan(a, b); while(TRIAL--) {
using namespace std; } ll a=Random(n-2)+1;
typedef double T; typedef if(Witness(a, n)) return false;
vector<T> vt; typedef }
return true;
vector<vt> vvt; 7.6 Miller-Rabin Primality Test }
T GaussJordan(vvt &a, vvt &b) { const
int n = a.size(); const int m = // Randomized Primality Test ( Miller-
b[0].size(); Rabin):
vi irow(n), icol(n), ipiv(n); T det = 1;
7.7 Playing with dates
// Error rate: 2ˆ(-TRIAL)
// Almost constant time. srand is needed // Routines for performing computations on
for (int i = 0; i < n; i++) { int pj = -1, pk dates. In these
= -1; #include "template.h"
routines,
for (int j = 0; j < n; j++) if (!ipiv[j]) ll ModularMultiplication(ll a, ll b // months are expressed as integers from 1
, ll m) { to 12, days are
for (int k = 0; k < n; k++) ll ret=0, c=a; expressed
if (!ipiv[k]) while(b) { // as integers from 1 to 31, and years are
if (pj == -1 || fabs(a[j][k]) > fabs(a[pj][pk])) { if(b&1) ret=(ret+c)%m; b>>=1; expressed as 4-digit
c=(c+c)%m; // integers.
pj = j; pk = k; } }
return ret; #include "template.h"
if (fabs(a[pj][pk]) < eps) { cerr << "Matrix } string dayOfWeek[] = {"Mon", "Tue",
is singular. " << endl; exit(0); } "Wed", "Thu", "Fri", "Sat", "
ll ModularExponentiation(ll a, ll n Sun"};
ipiv[pk]++; , ll m) {
swap(a[pj], a[pk]); ll ret=1, c=a; // converts Gregorian date to integer
swap(b[pj], b[pk]); while(n) { (Julian day number)
if(n&1) ret= int dateToInt (int m, int d, int y)
if (pj != pk) det *= -1; irow[i] = pj; ModularMultiplication(ret, c {
, m); return
icol[i] = pk; 1461 * (y + 4800 + (m - 14) /
n>>=1; c=ModularMultiplication( c, c, m); 12) / 4 +
T c = 1.0 / a[pk][pk]; det *= } 367 * (m - 2 - (m - 14) / 12 *
a[pk][pk]; a[pk][pk] = 1.0; return ret; 12) / 12 -
} 3 * ((y + 4900 + (m - 14) / 12)
for (int p = 0; p < n; p++) a[ pk][p] *= c; / 100) / 4 + d -
bool Witness(ll a, ll n) { 32075;
ll u=n-1; }
for (int p = 0; p < m; p++) b[ pk][p] *= c; int t=0;
for (int p = 0; p < n; p++) if (p != pk) { while(!(u&1)){u>>=1; t++;} // converts integer (Julian day number) to
ll x0=ModularExponentiation(a, u, n), x1; Gregorian date: month /day/year
c = a[p][pk];
a[p][pk] = 0; for(int i=1;i<=t;i++) { void intToDate (int jd, int &m, int &d, int &y){
for (int q = 0; q < n; q++) a x1=ModularMultiplication(x0, x0
21
[p][q] -= a[pk][q] * c; , n); int x, n, i, j;
MO,Radovinović, Sindičić
FER,PMF-
x = jd + 68569; rep1(i,0,n-1){ if(pf[i] == i){
n = 4 * x / 146097; if(1LL * i * i < N){
x -= (146097 * n + 3) / 4; fhash[i].F = (1LL * s[i] * p[ i].F + ( (i) ?
i = (4000 * (x + 1)) / 1461001; x -= 1461 * i / 4 - 31; fhash[i-1]. F : 0 ) ) % Mod; for(int j = i*i ; j < N ; j += (i*i) ){
mob[j] = 0;
j = 80 * x / 2447; fhash[i].S = (1LL * s[i] * p[ i].S + ( (i) ? }
fhash[i-1]. S : 0 ) ) % Mod; }
d = x - 2447 * j / 80; x = j / 11; } for(int j = i ; j < N ; j+=i)
m = j + 2 - 12 * x; } {
y = 100 * (n - 49) + i + x; void inbHash(){ mob[j] *= -1;
} rep2(i,n-1,0){ }
}
// converts integer (Julian day number) bhash[i].F = (1LL * s[i] * p[ n-i-1].F + ( }
to day of week (i<n-1) ? bhash[i+1].F : 0)) % Mod; }
string intToDay (int jd){ return
dayOfWeek[jd % 7]; } bhash[i].S = (1LL * s[i] * p[ n-i-1].S + (
(i<n-1) ? bhash[i+1].S : 0)) % Mod;
} 7.10 Mo's Algorithm
7.8 Hashing }
pii CalcFhash(int l,int r){ if(l > // Algorithm for sorting the quries in an order
#include "template.h" r)return mp(0,0); pii ret; which
// minimizes the time required from O(nˆ2) to
const int N = 1e5; ret.F = 1LL * (fhash[r].F - ((l )?fhash[l-1].F:0) + O((n + Q)sqrt(n))
// fhash[i] stores hash of s from s // + QlogQ This is done by sorting the
Mod) * ip[l].F % Mod; queries in
[0] to s[i], bhash stores hash // order of range on which they are
// for s[i] to s[n-1], calcFhash/ CalcBhash, ret.S = 1LL * (fhash[r].S - ((l )?fhash[l-1].S:0) +
calculate hash from performed
Mod) * ip[l].S % Mod; // We store the queries and sort them
// s[l] to s[r] in forward/backward direction return ret; using the compare
} // function cmp. Also we need to make
struct HASH{ pii CalcBhash(int l,int r){ if(l > an add function to
pii fhash[N],bhash[N]; pii r)return mp(0,0); pii ret; // calculate the value of range (l, r+1) from
p[N],ip[N]; string s; value of range
ret.F = 1LL * (bhash[l].F - ((r <n-1)?bhash[r+1].F:0) + // (l,r) and (l+1,r) from the value of (l,r), and a
int n; Mod)
remove
HASH(string str){ * ip[n-1-r].F % Mod; // function to calculate the value of (l-1, r)
s = str; n = s.size(); ret.S = 1LL * (bhash[l].S - ((r <n-1)?bhash[r+1].S:0) + from the value
} Mod) // of (l,r) and (l,r-1) from the value of (l,r) in
void init(){ constant time
p[0] = ip[0] = mp(1,1); * ip[n-1-r].S % Mod; return ret;
rep1(i,1,N-1){ } // S is the max integer number
}; which is less than sqrt(N);
p[i].F = 31LL * p[i-1].F % Mod; int main() {return 0;} int S = (int)(sqrt(N)); // Here see
if you want ll
p[i].S = 37LL * p[i-1].S % Mod; bool cmp(Query A, Query B)
7.9 Mobius function {
ip[i].F = 129032259LL * ip[i -1].F % Mod; if (A.l / S != B.l / S) return A.
void MOB(int n){ l / S < B.l / S;
ip[i].S = 621621626LL * ip[i -1].S % Mod; vector<int> mob(n); return A.r > B.r;
} }
for(int i = 1; i < n ; ++i)mob[i] = 1;
}
void infHash(){ for(int i = 2; i < N ; i++){
22
Sums Pn
s+n 1 , at most s:
n 1
Pollard- . Choose random x1, and let xi+1 = xi2 If p is prime and a is not divisible by p, then congruence xn a (mod p) has
1 (mod n). Test (
(p 1)= gcd(n;p 1) m
gcd(n; x2k+i x2k ) as possible n's factors for k = 0; 1; : : : Expected time to nd gcd(n; p 1) solutions if a 1 (mod p), and no solutions oth-
o
a factor: O( p m ), where m is smallest prime power in n's factorization. That's erwise. (Proof sketch: let g be a primitive root, and gi a (mod p), gu x d
1=4 k
O(n ) if you check n = p as a special case before factorization.
2n p
Fermat primes. A Fermat prime is a prime of form 2 +1. The only known )
Fermat primes are 3, 5, 17, 257, 65537. A number of form 2n + 1 is prime only .
if it is a Fermat prime. x
Perfect numbers. n > 1 is called perfect if it equals sum of its proper divi- n
sors and 1. Even n is perfect i n = 2p 1(2p 1) and 2p 1 is prime (Mersenne's).
No odd perfect numbers are yet found. a
Carmichael numbers. A positive composite n is a Carmichael number (an 1 (
1 (mod n) for all a: gcd(a; n) = 1), i n is square-free, and for all prime m
o
divisors p of n, p 1 divides n 1. a1 ak k a1 ak d
Number/sum of divisors. (p1 : : : pk ) = j=1(aj +1). (p1 : : : pk ) =
a +1
k pj j 1 . Q p
j=1 pj 1
)
Q Euler's phi function. (n) = m N; m n; gcd(m; n) = 1 .
(m) (n) gcd(m;n) jf 2 gj n
i
(mn) = (gcd(m;n)) . (pa) = pa 1(p 1). djn (d) = djn
(
d ) = n.
(n) ) = 1. g
Euler's theorem. a 1 (mod n), if gcd(a; nP P n
Wilson's theorem. p is prime i (p 1)! 1 (mod p). u
Mobius function. (1) = 1. (n) = 0, if n is not squarefree. (n) = ( 1)s,
if n is the product of s distinct primes. Let f, F be functions on positive integers. g
F (n) = f(d), then f(n) = (d)F ( n i
If for all n 2 N, n djn djn d ), and vice versa.
(n) = dn (d) d . d n (d)
P
= 1. P (
P j P
is multiplicative, then
j
(d)f(d) = (1 f(p)), 2
P P m
f Q o
If p n(1 + f(p)). djn pjn djn (d) f(d) =
d
j a
Q Legendre symbol. If p is an odd prime, a 2 Z, then equals 0, if
p a; 1 if a is a quadratic residue modulo p; and
p
MO,Radovinović, Sindičić
FER,PMF-
prime triples are given by: x = 2mn; y = m2 n2; z = m2 + n2 where m > n;
gcd(m; n) = 1 and m 6 n (mod 2). All other triples are multiples of these.
Equation x2 + y2 = 2z2 is equivalent to (x+2y )2 + (x 2 y )2 = z2.
Postage stamps/McNuggets problem. Let a, b be relatively-prime inte-gers.
There are exactly 12 (a 1)(b 1) numbers not of form ax + by (x; y 0), and the
largest is (a 1)(b 1) 1 = ab a b.
Fermat's two-squares theorem. Odd prime p can be represented as a sum
of two squares i p 1 (mod 4). A product of two sums of two squares is a sum of
two squares. Thus, n is a sum of two squares i every prime of form p = 4k + 3
occurs an even number of times in n's factorization.
Graph Theory
Euler's theorem. For any planar graph, V E + F = 1 + C, where V is the
number of graph's vertices, E is the number of edges, F is the number of faces
in graph's planar drawing, and C is the number of connected components.
Corollary: V E + F = 2 for a 3D polyhedron.
Vertex covers and independent sets. Let M, C, I be a max matching, a min
vertex cover, and a max independent set. Then jM j jCj = N jIj, with equality for
bipartite graphs. Complement of an MVC is always a MIS, and vice versa.
Given a bipartite graph with partitions (A; B), build a network: connect source
to A, and B to sink with edges of capacities, equal to the corresponding nodes'
weights, or 1 in the unweighted case. Set capacities of the original graph's
edges to the in nity. Let (S; T ) be a minimum s-t cut. Then a maximum(-
weighted) independent set is I = (A \ S) [ (B \ T ), and a minimum(-weighted)
vertex cover is C = (A \ T ) [ (B \ S).
Matrix-tree theorem. Let matrix T = [tij], where tij is the number of
multiedges between i and j, for i 6= j, and tii = degi. Number of spanning trees
of a graph is equal to the determinant of a matrix obtained by deleting any k-th
row and k-th column from T .
Euler tours. Euler tour in an undirected graph exists i the graph is con-
nected and each vertex has an even degree. Euler tour in a directed graph
exists i in-degree of each vertex equals its out-degree, and underlying
undirected graph is connected. Construction:
doit(u):
for each edge e = (u, v) in E, do: erase e, doit(v)
prepend u to the list of vertices in the tour
2-SAT. Build an implication graph with 2 vertices for each variable { for the
variable and its inverse; for each clause x _ y add edges (x; y) and (y; x). The for-
mula is satis able i x and x are in distinct SCCs, for all x. To nd a satis able
assignment, consider the graph's SCCs in topological order from sinks to sources
24
(i.e. Kosaraju's last step), assigning `true' to all variables of the current SCC (if Player must move in all games, and loses if can't move in some game. A
it hasn't been previously assigned `false'), and `false' to all inverses. position is losing if any of the games is in a losing position.
Randomized algorithm for non-bipartite matching. Let G be a sim-ple Misere Nim. A position with pile sizes a1; a2; : : : ; an 1, not all equal to 1, is
undirected graph with even jV (G)j. Build a matrix A, which for each edge (u; v)
losing i a1 a2 an = 0 (like in normal nim.) A position with n piles of size 1 is
2 E(G) has Ai;j = xi;j, Aj;i = xi;j, and is zero elsewhere. Tutte's theo-rem: G has losing i n is odd.
a perfect matching i det G (a multivariate polynomial) is identically zero.
Testing the latter can be done by computing the determinant for a few random Bit tricks
values of xi;j's over some eld. (e.g. Zp for a su ciently large prime p) Clearing the lowest 1 bit: x & (x - 1), all trailing 1's: x & (x + 1)
Prufer code of a tree. Label vertices with integers 1 to n. Repeatedly remove Setting the lowest 0 bit: x | (x + 1)
the leaf with the smallest label, and output its only neighbor's label, until only one Enumerating subsets of a bitmask m:
edge remains. The sequence has length n 2. Two isomorphic trees have the same x=0; do { ...; x=(x+1+˜m)&m; } while (x!=0);
sequence, and every sequence of integers from 1 and n corresponds to a tree. __builtin_ctz/__builtin_clz returns the number of trailing/leading zero bits.
n2
Corollary: the number of labelled trees with n vertices is n .
Erdos-Gallai theorem. A sequence of integers fd1; d2; : : : ; dng, with n 1 __builtin_popcount(unsigned x) counts 1-bits (slower than table lookups).
d1 d2 d n 0 is a degree sequence of some nundirected simple
min(k; d ) for For 64-bit unsigned integer type, use the su x `ll', i.e. __builtin_popcountll.
P;: : :i
all k = 1 ; 2 ; n 1. 1 k Pi=k+ 1 i
25
of all games are equal.
1e8 7 39 49 73 81 123 127 183 213
MO,Radovinović, Sindičić