diff --git a/algorithms/graph/dijkstra.cpp b/algorithms/graph/dijkstra.cpp
index e80f124cc70939b1eefd946705071821199f1ef7..05cefc8c05a2e93e91f08a03aec3696a2a6b7768 100644
--- a/algorithms/graph/dijkstra.cpp
+++ b/algorithms/graph/dijkstra.cpp
@@ -1,5 +1,11 @@
 /// Dijkstra
 ///
+/// Description:
+///   Dijkstra's algorithm for finding the shortest paths between nodes in a 
+/// graph. It works by greedily extending the shortest path at each step. \par
+///   Doesn't work with negative-weighted edges, for that, Bellman-Ford 
+/// algorithm must be used.
+///
 /// Time: O(E + V log V)
 /// Space: O(V + E)
 
@@ -18,7 +24,6 @@ struct Dijkstra {
     fill(all(dist), inf);
   }
 
-  // Returns shortest distance from s to d.
   int run(int s, int d) {
     set<ii> pq;
 
diff --git a/algorithms/graph/dinic.cpp b/algorithms/graph/dinic.cpp
index 0e96c6ee4b67ac4714da7233422210e6cda49652..fa3c52dbd27dd1aeb51e4ea5944a2f234c42c011 100644
--- a/algorithms/graph/dinic.cpp
+++ b/algorithms/graph/dinic.cpp
@@ -3,7 +3,7 @@
 /// Time: O(E * V^2)
 /// Space: O(V + E)
 ///
-/// Status: Tested (URI2882)
+/// Status: Tested (URI2882,URI2354)
 
 struct Dinic {
   struct Edge { int u, f, c, r; };
@@ -16,8 +16,8 @@ struct Dinic {
     N(N), depth(N), start(N), graph(N) {}
 
   void add_edge(int s, int t, int c) {
-    Edge forw = { t, 0, c, graph[t].size() };
-    Edge back = { s, 0, 0, graph[s].size() };
+    Edge forw = { t, 0, c, (int) graph[t].size() };
+    Edge back = { s, 0, 0, (int) graph[s].size() };
 
     graph[s].pb(forw);
     graph[t].pb(back);
diff --git a/algorithms/graph/edmonds_karp.cpp b/algorithms/graph/edmonds_karp.cpp
index 61703a5fd3a283b7569f9bc953a4233e77da8be4..02eea4db659a41e77e47e42ac66c7fa4c0448a2b 100644
--- a/algorithms/graph/edmonds_karp.cpp
+++ b/algorithms/graph/edmonds_karp.cpp
@@ -2,6 +2,8 @@
 ///
 /// Time: O(V * E^2)
 /// Space: O(V^2)
+///
+/// Status: Tested (URI2354)
 
 int rg[MAX][MAX];
 int graph[MAX][MAX];
diff --git a/algorithms/graph/ford_fulkerson.cpp b/algorithms/graph/ford_fulkerson.cpp
index b04b1ca953a907123557667251c133b800664bd5..90fd2bb133a80acd914dabdf04911efe853f3a61 100644
--- a/algorithms/graph/ford_fulkerson.cpp
+++ b/algorithms/graph/ford_fulkerson.cpp
@@ -2,6 +2,8 @@
 /// 
 /// Time: O(E * f)
 /// Space: O(V^2)
+///
+/// Status: Tested (URI2354)
 
 int rg[MAX][MAX];
 int graph[MAX][MAX];
diff --git a/algorithms/graph/hopcroft_karp.cpp b/algorithms/graph/hopcroft_karp.cpp
index b8abdceb193c3701da724cbf5800ef4f5178748d..78e2f89a4482d8f51206255f7ab419b7bf0fcc43 100644
--- a/algorithms/graph/hopcroft_karp.cpp
+++ b/algorithms/graph/hopcroft_karp.cpp
@@ -2,6 +2,10 @@
 ///
 /// Time: O(E * sqrt{V})
 /// Space: O(V + E)
+///
+/// Status: Tested (GCJ18 - Round2 - B)
+/// Caution: 
+///   - Assumes 1-indexed vertices in graph.
 
 vector<int> graph[MAX];
 
@@ -65,7 +69,7 @@ struct HopcroftKarp {
   int run() {
     int ans = 0;
 
-    while (bfs(L))
+    while (bfs())
       for (int l = 1; l <= L; ++l)
         if (matchL[l] == 0 && dfs(l))
           ans++;
diff --git a/algorithms/graph/kruskal.cpp b/algorithms/graph/kruskal.cpp
index b657194cac1cf87e2d8e18e7cdb4f41820846cb3..6963eb263b8005016d1ff3b09ed4ba60e0eba4e5 100644
--- a/algorithms/graph/kruskal.cpp
+++ b/algorithms/graph/kruskal.cpp
@@ -1,6 +1,8 @@
 /// Kruskal
 ///
-/// Time: O (E log V) 
+///
+///
+/// Time: O(E log V) 
 /// Space: O(E)
 /// 
 /// Include:
@@ -15,7 +17,8 @@ struct Kruskal {
 
   Kruskal(int N) : N(N), ds(N) {}
 
-  // Returns value of MST.
+  // Returns value of MST and fills mst vector with 
+  // the edges from the MST.
   int run(vector<iii> &mst) {
 
     // Sort by weight of the edges
diff --git a/algorithms/graph/lca.cpp b/algorithms/graph/lca.cpp
index 9ea2aea626b27beb0d55c832ee1d6f14c53648a9..70d2ed37b2849bb1ec4e5a01ecbe0bf3830858b2 100644
--- a/algorithms/graph/lca.cpp
+++ b/algorithms/graph/lca.cpp
@@ -1,5 +1,17 @@
 /// Lowest Common Ancestor (LCA)
 ///
+/// Description:
+///   The LCA between two nodes in a tree is a node that is an ancestor to both
+/// nodes with the lowest height possible. \par
+///   The algorithm works by following the path up the tree from both nodes 
+/// "simultaneously" until a common node is found. The naive approach for that
+/// would be $O(n)$ in the worst case. To improve that, this implementation 
+/// uses "binary lifting" which is a way of figuring out the right number of 
+/// up-moves needed to find the LCA by following the binary representation of
+/// the distance to the destination (similar to the "binary search by jumping"),
+/// but, for that, a preprocessing must be done to set every parent at a $2^i$
+/// distance.
+///
 /// Time:
 ///   - preprocess: O(V log V)
 ///   - query:      O(log V)
diff --git a/algorithms/string/kmp.cpp b/algorithms/string/kmp.cpp
index 48d2219648444e6a63baf176e936961bbe587932..91e38f5ef7b0a5b2cf366f87efc4f71776969f86 100644
--- a/algorithms/string/kmp.cpp
+++ b/algorithms/string/kmp.cpp
@@ -4,44 +4,37 @@
 ///   - preprocess: O(m)
 ///   - search:     O(n)
 /// Space: O(n + m)
+///
+/// Status: Tested (URI2350)
 
 struct KMP {
   string patt;
   vector<int> table;
 
   KMP(string patt) :
-    patt(patt), table(patt.size())
+    patt(patt), table(patt.size()+1)
   { preprocess(); }
 
   void preprocess() {
-    int i = 1, len = 0;
+    fill(all(table), -1);
 
-    while (i < patt.size()) {
-      if (patt[i] == patt[len])
-        table[i++] = ++len;
-      else if (len)
-        len = table[len - 1];
-      else
-        table[i++] = 0;
+    for (int i = 0, j = -1; i < patt.size(); ++i) {
+      while (j >= 0 && patt[i] != patt[j]) 
+        j = table[j];
+      table[i + 1] = ++j;
     }
   }
 
   vector<int> search(const string &txt) {
-    int i = 0, j = 0;
     vector<int> occurs;
 
-    while (i < txt.size()) {
-      if (patt[j] == txt[i])
-        i++, j++;
-
+    for (int i = 0, j = 0; i < txt.size(); ++i) {
+      while (j >= 0 && txt[i] != patt[j]) 
+        j = table[j];
+      j++;
       if (j == patt.size()) {
-        occurs.push_back(i - j);
-        j = table[j - 1];
-      } else if (i < txt.size() && patt[j] != txt[i]) {
-        if (j > 0) 
-          j = table[j - 1];
-        else 
-          i++;
+        occurs.pb(i - j);
+        j = table[j];
       }
     }
 
diff --git a/caderno.pdf b/caderno.pdf
index 0b8ead1ae696fa179c417ea1e11169ea7900fd8a..1cae42f8e9135fa0a3d6179c538151d700127988 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/contests/CodeJam/2018/Round 2/A.cpp b/contests/CodeJam/2018/Round 2/A.cpp
index 86fd46cd04fe69d54a34b0f9099100e36dbe3e31..3c2e56cee8d4515324ce81509931fe07013cc1fb 100644
--- a/contests/CodeJam/2018/Round 2/A.cpp	
+++ b/contests/CodeJam/2018/Round 2/A.cpp	
@@ -26,48 +26,39 @@ int main() {
   int t; cin >> t;
   for (int cas = 1; cas <= t; ++cas) {
     int c; cin >> c;
-    vector<int> v(c);
-
-    int grt = 0;
-    for (auto &i : v) {
-      cin >> i;
-      grt = max(grt, i);
+    vector<int> v(c + 1);
+    int sum = 0;
+    for (int i = 1; i <= c; ++i) {
+      cin >> v[i];
+      sum += v[i];
     }
 
     cout << "Case #" << cas << ": ";
-    if (v[0] == 0 || v[c-1] == 0) {
+    if (v[1] == 0 || v[c] == 0 || sum != c) {
       cout << "IMPOSSIBLE" << ende;
       continue;
     }
 
-    vector<int> dest(c);
-    int l = 0, r = c - 1;
-    for (int i = 0; i < 1000; ++i) {
-      if (l >= r) break;
-      if (v[l] > 0) {
-        for (int i = 0; i < v[l]; ++i)
-          dest[l+i] = l;
-        l += v[l];
-      }
-
-      if (v[r] > 0) {
-        for (int i = 0; i < v[r]; ++i)
-          dest[r-i] = r;
-        r -= v[r];
-      }
-    }
-
-
-    vector<string> ans(grt, string(c, '.'));
+    int k = 1;
+    vector<int> orig(c + 1);
+    for (int i = 1; i <= c; ++i)
+      for (int j = 0; j < v[i]; ++j)
+        orig[k++] = i;
 
-    vector<int> curr(c);
+    int grt = 0;
+    for (int i = 1; i <= c; ++i)
+      grt = max(grt, abs(orig[i] - i) + 1);
+    
+    vector<string> ans(grt, string(c + 1, '.'));
+    vector<int> curr(c + 1);
     iota(all(curr), 0);
+
     for (int i = 0; i < grt; ++i) {
-      for (int j = 0; j < c; ++j) {
-        if (curr[j] > dest[j]) {
+      for (int j = 1; j <= c; ++j) {
+        if (curr[j] > orig[j]) {
           ans[i][curr[j]] = '/';
           curr[j]--;
-        } else if (curr[j] < dest[j]) {
+        } else if (curr[j] < orig[j]) {
           ans[i][curr[j]] = '\\';
           curr[j]++;
         }
@@ -75,16 +66,20 @@ int main() {
     }
 
     bool poss = true;
-    for (int i = 0; i < c; ++i)
-      if (curr[i] != dest[i])
+    for (int i = 1; i <= c; ++i)
+      if (curr[i] != orig[i])
         poss = false;
 
     if (poss) {
       cout << grt << ende;
-      for (auto i : ans)
-        cout << i << ende;
-    } else
+      for (int i = 0; i < grt; ++i) {
+        for (int j = 1; j <= c; ++j)
+          cout << ans[i][j];
+        cout << ende;
+      }
+    } else {
       cout << "IMPOSSIBLE" << ende;
+    }
   }
 
   return 0;
diff --git a/contests/CodeJam/2018/Round 2/C.cpp b/contests/CodeJam/2018/Round 2/C.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..708257044ed51a868869c11ed901c84a0d38bc90
--- /dev/null
+++ b/contests/CodeJam/2018/Round 2/C.cpp	
@@ -0,0 +1,127 @@
+#include <bits/stdc++.h>
+
+#define MAX 221
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+vector<int> graph[MAX];
+
+struct HopcroftKarp {
+  int L, R;
+  vector<int> dist;
+  vector<int> matchL, matchR;
+
+  HopcroftKarp(int L, int R) :
+    L(L), R(R), dist(L),
+    matchL(L), matchR(R)
+  { init(); }
+
+  void init() {
+    fill(all(matchL), 0);
+    fill(all(matchR), 0);
+  }
+
+  bool bfs() {
+    queue<int> Q;
+
+    for (int l = 1; l <= L; ++l)
+      if (matchL[l] == 0) {
+        dist[l] = 0;
+        Q.push(l);
+      } else {
+        dist[l] = inf;
+      }
+
+    dist[0] = inf;
+    while (!Q.empty()) {
+      int l = Q.front(); Q.pop();
+
+      if (dist[l] < dist[0])
+        for (auto r : graph[l])
+          if (dist[matchR[r]] == inf) {
+            dist[matchR[r]] = dist[l] + 1;
+            Q.push(matchR[r]);
+          }
+    }
+
+    return (dist[0] != inf);
+  }
+
+  bool dfs(int l) {
+    if (l == 0)
+      return true;
+
+    for (auto r : graph[l])
+      if (dist[matchR[r]] == dist[l] + 1)
+        if (dfs(matchR[r])) {
+          matchR[r] = l;
+          matchL[l] = r;
+          return true;
+        }
+
+    dist[l] = inf;
+    return false;
+  }
+
+  int run() {
+    int ans = 0;
+
+    while (bfs())
+      for (int l = 1; l <= L; ++l)
+        if (matchL[l] == 0 && dfs(l))
+          ans++;
+
+    return ans;
+  }
+};
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int t; cin >> t;
+  for (int cas = 1; cas <= t; ++cas) {
+    int n; cin >> n;
+    vector<vector<int>> mat(n, vector<int>(n));
+    for (auto &i : mat)
+      for (auto &j : i) 
+        cin >> j;
+
+    cout << "Case #" << cas << ": ";
+    int ans = 0;
+    for (int i = -n; i <= n; ++i) {
+      for (int j = 0; j < MAX; ++j)
+        graph[j].clear();
+
+      int num = 0;
+      for (int j = 0; j < n; ++j)
+        for (int k = 0; k < n; ++k)
+          if (mat[j][k] == i) {
+            num++;
+            graph[j + 1].pb(n + k + 1);
+          }
+
+      HopcroftKarp hk(n+n+1, n+n+1);
+      ans += (num - hk.run());
+    }
+    cout << ans << ende;
+  }
+
+  return 0;
+}
diff --git a/contests/ICPC_LA16/A.cpp b/contests/ICPC_LA16/A.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb471d2be6ff3758b15f4279b8dc8eefbf346e08
--- /dev/null
+++ b/contests/ICPC_LA16/A.cpp
@@ -0,0 +1,32 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  vector<int> v(4);
+  for (auto &i : v) cin >> i;
+  sort(all(v));
+
+  cout << abs((v[0] + v[3]) - (v[1] + v[2])) << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA16/B.cpp b/contests/ICPC_LA16/B.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7d2f6bd6c8299a774490ab5af0f62c7b5e11f8c
--- /dev/null
+++ b/contests/ICPC_LA16/B.cpp
@@ -0,0 +1,72 @@
+#include <bits/stdc++.h>
+
+#define MAX 101010
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+set<int> graph[MAX];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, m, a, b; cin >> n >> m >> a >> b;
+  for (int i = 0; i < m; ++i) {
+    int x, y; cin >> x >> y;
+    graph[x].insert(y);
+    graph[y].insert(x);
+  }
+
+  set<ii> S;
+  for (int i = 1; i <= n; ++i)
+    S.insert(ii(graph[i].size(), i));
+
+  bool ended = false;
+  while (!ended) {
+    ended = true;
+    while (S.size() && S.begin()->fi < a) {
+      ii u = *(S.begin()); S.erase(S.begin());
+
+      for (auto i : graph[u.se]) {
+        S.erase(ii(graph[i].size(), i));
+        graph[i].erase(u.se);
+        S.insert(ii(graph[i].size(), i));
+      }
+
+      graph[u.se].clear();
+      ended = false;
+    }
+
+    while (S.size() && S.size() - prev(S.end())->fi - 1 < b) {
+      ii u = *(prev(S.end())); S.erase(prev(S.end()));
+
+      for (auto i : graph[u.se]) {
+        S.erase(ii(graph[i].size(), i));
+        graph[i].erase(u.se);
+        S.insert(ii(graph[i].size(), i));
+      }
+
+      graph[u.se].clear();
+      ended = false;
+    }
+  }
+
+  cout << S.size() << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA16/D.cpp b/contests/ICPC_LA16/D.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..46f69ec9705ea5f0456454bcfcf7e64615a014b9
--- /dev/null
+++ b/contests/ICPC_LA16/D.cpp
@@ -0,0 +1,53 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+#define to_rad(x) (x * M_PI) / 180.0
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+using dd = pair<double,double>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+  cout << setprecision(3) << fixed;
+
+  int n; cin >> n;
+  vector<int> v(n);
+  for (auto &i : v) cin >> i;
+  sort(all(v));
+
+  vector<int> u(n);
+  int a = 0, b = n - 1;
+  for (int i = 0; i < n; ++i) {
+    if (i % 2) u[b--] = v[i];
+    else u[a++] = v[i];
+  }
+ 
+  vector<dd> points(n);
+  for (int i = 0; i < n; ++i) {
+    points[i].fi = u[i] * cos(to_rad((360.0 / n) * (i + 1)));
+    points[i].se = u[i] * sin(to_rad((360.0 / n) * (i + 1)));
+  }
+
+  double sum = 0.0;
+  for (int i = 0; i < n; ++i)
+    sum += points[i].fi * points[(i+1) % n].se - points[i].se * points[(i+1)%n].fi;
+  cout << sum / 2.0 << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA16/F.cpp b/contests/ICPC_LA16/F.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8d1ea908689fd6b99a67e8e9dde8c10740629e4f
--- /dev/null
+++ b/contests/ICPC_LA16/F.cpp
@@ -0,0 +1,37 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, c, s; cin >> n >> c >> s; s--;
+  int curr = 0, ans = curr == s;
+  for (int i = 0; i < c; ++i) {
+    int x; cin >> x;
+    curr = ((curr + x) + n) % n;
+    if (curr == s)
+      ans++;
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA16/G.cpp b/contests/ICPC_LA16/G.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..67c7bb3e9efc863a10167b0e91f1e8387eded30e
--- /dev/null
+++ b/contests/ICPC_LA16/G.cpp
@@ -0,0 +1,85 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+struct KMP {
+  vector<int> patt;
+  vector<int> table;
+
+  KMP(vector<int> patt) :
+    patt(patt), table(patt.size()+1)
+  { preprocess(); }
+
+  void preprocess() {
+    fill(all(table), -1);
+
+    for (int i = 0, j = -1; i < patt.size(); ++i) {
+      while (j >= 0 && patt[i] != patt[j] && (patt[j] || patt[i] <= j))
+        j = table[j];
+      table[i + 1] = ++j;
+    }
+  }
+
+  int search(const vector<int> &txt) {
+    int ans = 0;
+    for (int i = 0, j = 0; i < txt.size(); ++i) {
+      while (j >= 0 && txt[i] != patt[j] && (patt[j] || txt[i] <= j))
+        j = table[j];
+      ++j;
+      if (j == patt.size()) {
+        ans++;
+        j = table[j];
+      }
+    }
+
+    return ans;
+  }
+};
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string s; cin >> s;
+  int n; cin >> n;
+  vector<int> v(n);
+  for (auto &i : v) {
+    cin >> i; --i; 
+  }
+
+  vector<int> last(30, -1);
+  vector<int> A(s.size()), B(n);
+  for (int i = 0; i < s.size(); ++i) {
+    if (last[s[i] - 'a'] == -1) A[i] = 0;
+    else A[i] = i - last[s[i] - 'a'];
+    last[s[i] - 'a'] = i;
+  }
+
+  fill(all(last), -1);
+  for (int i = 0; i < v.size(); ++i) {
+    if (last[v[i]] == -1) B[i] = 0;
+    else B[i] = i - last[v[i]];
+    last[v[i]] = i;
+  }
+
+  KMP kmp(B);
+  cout << kmp.search(A) << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA16/J.cpp b/contests/ICPC_LA16/J.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6794af1284533afd1ec9e065942bae2cd28877e
--- /dev/null
+++ b/contests/ICPC_LA16/J.cpp
@@ -0,0 +1,42 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n; cin >> n;
+  if (n == 2) return cout << 2 << ende, 0;
+  for (int i = n; i >= 0; --i) {
+    if (i % 2 == 0) continue;
+    bool done = true;
+    for (int j = 3; j * j <= n; j += 2)
+      if (i % j == 0) {
+        done = false;
+        break;
+      }
+
+    if (done)
+      return cout << i << ende, 0;
+  }
+
+  return 0;
+}
diff --git a/contests/ICPC_LA16/K.cpp b/contests/ICPC_LA16/K.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..96356ddf0604c5ed403b8f8da6e91315d26521f7
--- /dev/null
+++ b/contests/ICPC_LA16/K.cpp
@@ -0,0 +1,136 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+struct Dinic {
+  struct Edge { int u, f, c, r; };
+
+  int N;
+  vector<int> depth, start;
+  vector<vector<Edge>> graph;
+
+  Dinic(int N) : 
+    N(N), depth(N), start(N), graph(N) {}
+
+  void add_edge(int s, int t, int c) {
+    Edge forw = { t, 0, c, (int) graph[t].size() };
+    Edge back = { s, 0, 0, (int) graph[s].size() };
+
+    graph[s].pb(forw);
+    graph[t].pb(back);
+  }
+
+  bool bfs(int s, int t) {
+    queue<int> Q;
+    Q.push(s);
+
+    fill(all(depth), -1);
+    depth[s] = 0;
+
+    while (!Q.empty()) {
+      int v = Q.front(); Q.pop();
+
+      for (auto i : graph[v])
+        if (depth[i.u] == -1 && i.f < i.c) {
+          depth[i.u] = depth[v] + 1;
+          Q.push(i.u);
+        }
+    }
+
+    return depth[t] != -1;
+  }
+
+  int dfs(int s, int t, int f) {
+    if (s == t)
+      return f;
+
+    for ( ; start[s] < graph[s].size(); ++start[s]) {
+      Edge &e = graph[s][start[s]];
+
+      if (depth[e.u] == depth[s] + 1 && e.f < e.c) {
+        int min_f = dfs(e.u, t, min(f, e.c - e.f));
+
+        if (min_f > 0) {
+          e.f += min_f;
+          graph[e.u][e.r].f -= min_f;
+          return min_f;
+        }
+      }
+    }
+
+    return 0;
+  }
+
+  int run(int s, int t) {
+    int ans = 0;
+    while (bfs(s, t)) {
+      fill(all(start), 0);
+
+      while (int flow = dfs(s, t, inf))
+        ans += flow;
+    }
+
+    return ans;
+  }
+};
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n; cin >> n;
+  vector<ii> v(n+1);
+  for (int i = 1; i <= n; ++i)
+    cin >> v[i].fi >> v[i].se;
+
+  int ans = 0;
+  for (int i = 1; i <= n; ++i) {
+    int votes = 0, pass = 0;
+    int s = 0, t = 2*n + 1;
+    Dinic dinic(t + 1);
+
+    for (int j = 1; j <= n; ++j) {
+      if (i == j) 
+        continue;
+
+      if (v[j].fi == i || v[j].se == i) {
+        votes++;
+        continue;
+      }
+      
+      dinic.add_edge(s, j, 1);
+      dinic.add_edge(j, v[j].fi + n, 1);
+      dinic.add_edge(j, v[j].se + n, 1);
+      pass++;
+    }
+
+    for (int j = 1; j <= n; ++j)
+      if (v[i].fi == j || v[i].se == j)
+        dinic.add_edge(j + n, t, votes - 2);
+      else
+        dinic.add_edge(j + n, t, votes - 1);
+
+    if (dinic.run(s, t) < pass)
+      ans++;
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/notebook/gen_latex.py b/notebook/gen_latex.py
index 76eee468bb98a4d2461bd6897b02525ea58d0095..4871f39d0754c646f75765d1c458260d8533fe6c 100644
--- a/notebook/gen_latex.py
+++ b/notebook/gen_latex.py
@@ -49,7 +49,7 @@ class LatexGenerator:
             self.header = {}
             self.code, self.raw_header = [], []
             self.sections = ['Description', 'Time', 'Space', 'Include', 
-                    'Status']
+                    'Status', 'Caution']
 
             self._parse_source(source)
             self._parse_header()