From 53430d28d452fee8fb64d88ca378b9e0a2b62153 Mon Sep 17 00:00:00 2001
From: Bruno Freitas Tissei <bft15@inf.ufpr.br>
Date: Wed, 11 Sep 2019 16:06:07 -0300
Subject: [PATCH] Organize geometry and add SBC15

Signed-off-by: Bruno Freitas Tissei <bft15@inf.ufpr.br>
---
 algorithms/geometry/circle.cpp              |  53 ++++-----
 algorithms/geometry/convex_hull.cpp         |  21 ++--
 algorithms/geometry/geometry_primitives.cpp | 120 --------------------
 algorithms/geometry/point.cpp               |  50 ++++++++
 algorithms/geometry/polygon.cpp             |  65 +++++++++++
 algorithms/geometry/primitives.cpp          |   8 ++
 algorithms/geometry/rotating_calipers.cpp   |  41 -------
 algorithms/geometry/segment.cpp             |  48 ++++++++
 contests/Cadernaveis/LA5138.cpp             |  68 ++++++-----
 contests/SBC15/A.cpp                        |  65 +++++++++++
 contests/SBC15/B.cpp                        |  40 +++++++
 contests/SBC15/C.cpp                        |  30 +++++
 contests/SBC15/D.cpp                        |  92 +++++++++++++++
 contests/SBC15/E.cpp                        |  52 +++++++++
 contests/SBC15/F.cpp                        |  41 +++++++
 contests/SBC15/J.cpp                        |  40 +++++++
 contests/SBC15/K.cpp                        |  67 +++++++++++
 17 files changed, 675 insertions(+), 226 deletions(-)
 delete mode 100644 algorithms/geometry/geometry_primitives.cpp
 create mode 100644 algorithms/geometry/point.cpp
 create mode 100644 algorithms/geometry/polygon.cpp
 create mode 100644 algorithms/geometry/primitives.cpp
 delete mode 100644 algorithms/geometry/rotating_calipers.cpp
 create mode 100644 algorithms/geometry/segment.cpp
 create mode 100644 contests/SBC15/A.cpp
 create mode 100644 contests/SBC15/B.cpp
 create mode 100644 contests/SBC15/C.cpp
 create mode 100644 contests/SBC15/D.cpp
 create mode 100644 contests/SBC15/E.cpp
 create mode 100644 contests/SBC15/F.cpp
 create mode 100644 contests/SBC15/J.cpp
 create mode 100644 contests/SBC15/K.cpp

diff --git a/algorithms/geometry/circle.cpp b/algorithms/geometry/circle.cpp
index 91f3555..179a8ba 100644
--- a/algorithms/geometry/circle.cpp
+++ b/algorithms/geometry/circle.cpp
@@ -1,16 +1,16 @@
 /// Circle
 
 struct Circle {
-  Point<double> c;
+  Point<> c;
   double r;
 
-  Circle(Point<double> c, double r) : c(c), r(r) {}
+  Circle(Point<> c, double r) : c(c), r(r) {}
 
   // Circumcircle
-  Circle(Point<double> a, Point<double> b, Point<double> c) {
-    Point<double> u((b - a).y, -(b - a).x);
-    Point<double> v((c - a).y, -(c - a).x);
-    Point<double> n = (c - b)*0.5;
+  Circle(Point<> a, Point<> b, Point<> c) {
+    Point<> u((b - a).y, -(b - a).x);
+    Point<> v((c - a).y, -(c - a).x);
+    Point<> n = (c - b)*0.5;
 
     double t = u.cross(n) / v.cross(u);
 
@@ -18,30 +18,31 @@ struct Circle {
     this->r = dist(this->c, a);
   }
 
-  bool contains(Point<double> p) {
-    return (dist(c, p) <= r + EPS);
-  }
-};
-
-// Minumum enclosing circle
-Circle min_enclosing(vector<Point<double>> p) {
-  random_shuffle(all(p));
-  Circle C(p[0], 0.0);
+  // Minimum enclosing circle: O(n)
+  Circle(vector<Point<>> p) {
+    random_shuffle(all(p));
+    Circle C(p[0], 0.0);
 
-  for (int i = 0; i < p.size(); ++i) {
-    if (C.contains(p[i])) continue;
-    C = Circle(p[i], 0.0);
+    for (int i = 0; i < p.size(); ++i) {
+      if (C.contains(p[i])) continue;
+      C = Circle(p[i], 0.0);
 
-    for (int j = 0; j < i; ++j) {
-      if (C.contains(p[j])) continue;
-      C = Circle((p[j] + p[i])*0.5, 0.5*dist(p[j], p[i]));
+      for (int j = 0; j < i; ++j) {
+        if (C.contains(p[j])) continue;
+        C = Circle((p[j] + p[i])*0.5, 0.5*dist(p[j], p[i]));
 
-      for (int k = 0; k < j; ++k) {
-        if (C.contains(p[k])) continue;
-        C = Circle(p[j], p[i], p[k]);
+        for (int k = 0; k < j; ++k) {
+          if (C.contains(p[k])) continue;
+          C = Circle(p[j], p[i], p[k]);
+        }
       }
     }
+
+    this->c = C.c;
+    this->r = C.r;
   }
 
-  return C;
-}
+  bool contains(Point<double> p) {
+    return (dist(c, p) <= r + EPS);
+  }
+};
diff --git a/algorithms/geometry/convex_hull.cpp b/algorithms/geometry/convex_hull.cpp
index 1e29a4e..279e717 100644
--- a/algorithms/geometry/convex_hull.cpp
+++ b/algorithms/geometry/convex_hull.cpp
@@ -3,31 +3,28 @@
 /// Time: O(n log n)
 /// Space: O(n)
 
-using point = pair<double,double>;
-
-bool cw(point a, point b, point c) {
-  return (b.fi - a.fi) * (c.se - a.se) - \
-         (b.se - a.se) * (c.fi - a.fi) < 0;
+bool cw(Point<> a, Point<> b, Point<> c) {
+  return (b - a).cross(c - a) <= 0;
 }
 
-vector<point> convex_hull(vector<point> &v) {
+vector<Point<>> convex_hull(vector<Point<>> &v) {
   int k = 0;
-  vector<point> ans(v.size() * 2);
+  vector<Point<>> ans(v.size() * 2);
 
-  sort(all(v), [](const point &a, const point &b) {
-    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+  sort(all(v), [](const Point<> &a, const Point<> &b) {
+    return (a.x == b.x) ? (a.y < b.y) : (a.x < b.x);
   });
 
   for (int i = 0; i < v.size(); ++i) {
-    for (; k >= 2 && !cw(ans[k-2], ans[k-1], v[i]); --k);
+    for (; k >= 2 && cw(ans[k-2], ans[k-1], v[i]); --k);
     ans[k++] = v[i];
   }
 
   for (int i = v.size() - 2, t = k + 1; i >= 0; --i) {
-    for (; k >= t && !cw(ans[k-2], ans[k-1], v[i]); --k);
+    for (; k >= t && cw(ans[k-2], ans[k-1], v[i]); --k);
     ans[k++] = v[i];
   }
 
-  ans.resize(k - 1);
+  ans.resize(k);
   return ans;
 }
diff --git a/algorithms/geometry/geometry_primitives.cpp b/algorithms/geometry/geometry_primitives.cpp
deleted file mode 100644
index 041afc2..0000000
--- a/algorithms/geometry/geometry_primitives.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/// Geometry Primitives
-
-#define to_deg(x) ((x * 180.0) / M_PI)
-#define to_rad(x) ((x * M_PI) / 180.0)
-
-template <typename T>
-struct Point {
-  T x, y; 
-
-  Point() {}
-  Point(T x, T y) : x(x), y(y) {}
-
-  Point operator+(Point p) { return Point(x+p.x, y+p.y); }
-  Point operator-(Point p) { return Point(x-p.x, y-p.y); }
-  Point operator*(T s) { return Point(x*s, y*s); }
-
-  T dot(Point p)   { return (x*p.x) + (y*p.y); }
-  T cross(Point p) { return (x*p.y) - (y*p.x); }
-
-  // Returns angle between this and p:
-  // atan2(y, x) is in the range [-180,180]. To 
-  // get [0, 360], atan2(-y, -x) + 180 is used
-  T angle(Point p) {
-    return to_deg(atan2(-cross(p), -dot(p))) + 180.0;
-  }
-  
-  // Returns cosine value between this and p.
-  T cosine(Point p) {
-    return (dot(p) / (sqrt(dot(*this))*sqrt(p.dot(p))));
-  }
-
-  // Returns sine value between this and p.
-  T sine(Point p) {
-    return (cross(p) / (sqrt(dot(*this))*sqrt(p.dot(p))));
-  }
-
-  // Returns whether point is inside the triable
-  // abc or not.
-  bool inside_triagle(Point a, Point b, Point c) {
-    bool c1 = (*this - b).cross(a - b) < 0;
-    bool c2 = (*this - c).cross(b - c) < 0;
-    bool c3 = (*this - a).cross(c - a) < 0;
-    return c1 == c2 && c1 == c3;
-  }
-
-  // Finds orientation of ordered triplet (a,b,c).
-  // Colinear (0), Clockwise (1), Counterclockwise (2)
-  static int orientation(Point a, Point b, Point c) {
-    T val = (b - a).cross(c - b);
-    if (val == 0) return 0;
-    return (val > 0) ? 1 : 2;
-  }
-};
-
-double dist(Point<double> a, Point<double> b) {
-  return hypot(a.x - b.x, a.y - b.y);
-}
-
-template <typename T>
-struct Segment {
-  Point<T> a, b;
-
-  Segment(Point a, Point b) : a(a), b(b) {}
-
-  // Checks if points p and q are on the same side 
-  // of the segment.
-  bool same_side(Point p, Point q) { 
-    T cpp = (p - a).cross(b - a);
-    T cpq = (q - a).cross(b - a);
-    return ((cpp > 0 && cpq > 0) || 
-            (cpp < 0 && cpq < 0));
-  }
-
-  // Checks if point p is on the segment.
-  bool on_segment(Point p) {
-    return (p.x <= max(a.x, b.x) && 
-            p.x >= min(a.x, b.x) &&
-            p.y <= max(a.y, b.y) && 
-            p.y >= min(a.y, b.y));
-  }
-
-  // Checks if segment intersects with s.
-  bool intersect(Segment s) {
-    int o1 = Point::orientation(  a,   b, s.a);
-    int o2 = Point::orientation(  a,   b, s.b);
-    int o3 = Point::orientation(s.a, s.b,   a);
-    int o4 = Point::orientation(s.a, s.b,   b);
-
-    if (o1 != o2 && o3 != o4)
-      return true;
-
-    if (o1 == 0 && on_segment(s.a)) return true;
-    if (o2 == 0 && on_segment(s.b)) return true;
-    if (o3 == 0 && s.on_segment(a)) return true;
-    if (o4 == 0 && s.on_segment(b)) return true;
-
-    return false;
-  }
-};
-
-template <typename T>
-struct Polygon {
-  vector<Point<T>> v;
-
-  Polygon() {}
-  Polygon(vector<Point> v) : v(v) {} 
-  
-  // Adds a vertex to the polygon.
-  void add_point(Point p) { v.pb(p); }
-
-  // Returns area of polygon (only works when vertices
-  // are sorted in clockwise or counterclockwise order).
-  double area() {
-    double ans = 0;
-    for (int i = 0; i < v.size(); ++i)
-      ans += v[i].cross(v[(i + 1) % v.size()]);
-
-    return fabs(ans) / 2.0;
-  }
-};
diff --git a/algorithms/geometry/point.cpp b/algorithms/geometry/point.cpp
new file mode 100644
index 0000000..a3f66ab
--- /dev/null
+++ b/algorithms/geometry/point.cpp
@@ -0,0 +1,50 @@
+/// Point
+
+template <typename T = double>
+struct Point {
+  T x, y; 
+
+  Point() {}
+  Point(T x, T y) : x(x), y(y) {}
+
+  Point operator+(Point p) { return Point(x+p.x, y+p.y); }
+  Point operator-(Point p) { return Point(x-p.x, y-p.y); }
+  Point operator*(T s) { return Point(x*s, y*s); }
+
+  T dot(Point p)   { return (x*p.x) + (y*p.y); }
+  T cross(Point p) { return (x*p.y) - (y*p.x); }
+
+  // Returns angle between this and p:
+  // atan2(y, x) is in the range [-180,180]. To 
+  // get [0, 360], atan2(-y, -x) + 180 is used
+  T angle(Point p) {
+    return to_deg(atan2(-cross(p), -dot(p))) + 180.0;
+  }
+
+  // Returns cosine value between this and p.
+  T cosine(Point p) {
+    return (dot(p) / (sqrt(dot(*this))*sqrt(p.dot(p))));
+  }
+
+  // Returns sine value between this and p.
+  T sine(Point p) {
+    return (cross(p) / (sqrt(dot(*this))*sqrt(p.dot(p))));
+  }
+
+  // Returns whether point is inside the triable
+  // abc or not.
+  bool inside_triagle(Point a, Point b, Point c) {
+    bool c1 = (*this - b).cross(a - b) < 0;
+    bool c2 = (*this - c).cross(b - c) < 0;
+    bool c3 = (*this - a).cross(c - a) < 0;
+    return c1 == c2 && c1 == c3;
+  }
+
+  // Finds orientation of ordered triplet (a,b,c).
+  // Colinear (0), Clockwise (1), Counterclockwise (2)
+  static int orientation(Point<> a, Point<> b, Point<> c) {
+    T val = (b - a).cross(c - b);
+    if (val == 0) return 0;
+    return (val > 0) ? 1 : 2;
+  }
+};
diff --git a/algorithms/geometry/polygon.cpp b/algorithms/geometry/polygon.cpp
new file mode 100644
index 0000000..97db8be
--- /dev/null
+++ b/algorithms/geometry/polygon.cpp
@@ -0,0 +1,65 @@
+/// Polygon
+
+template <typename T = double>
+struct Polygon {
+  vector<Point<T>> v;
+
+  Polygon() {}
+  Polygon(vector<Point<T>> v) : v(v) {} 
+
+  // Adds a vertex to the polygon.
+  void add_point(Point<T> p) { v.pb(p); }
+
+  // Returns area of polygon (only works when vertices
+  // are sorted in clockwise or counterclockwise order).
+  double area() {
+    double ans = 0;
+    for (int i = 0; i < v.size(); ++i)
+      ans += v[i].cross(v[(i + 1) % v.size()]);
+
+    return fabs(ans) / 2.0;
+  }
+
+  // Rotating Calipers
+  double width() {
+    vector<Point<>> h = convex_hull(v);
+
+    int n = h.size() - 1;
+    double ans = 1e14;
+
+    h[0] = h[n];
+    for (int i = 1, j = 1; i <= n; ++i) {
+      while ((h[i] - h[i-1]).cross(h[j%n+1] - h[i-1]) > 
+          (h[i] - h[i-1]).cross(h[j] - h[i-1]))
+        j = j % n + 1;
+
+      Segment<> seg(h[i], h[i-1]);
+      ans = min(ans, seg.dist(h[j]));
+    }
+
+    return ans;
+  }
+
+  // Rotating Calipers
+  double diameter() {
+    vector<Point<>> h = convex_hull(v);
+
+    if (h.size() == 1) return 0;
+    if (h.size() == 2) return dist(h[0], h[1]);
+
+    int n = h.size() - 1;
+    double ans = -1e14;
+
+    h[0] = h[n];
+    for (int i = 1, j = 1; i <= n; ++i) {
+      while ((h[i] - h[i-1]).cross(h[j%n+1] - h[i-1]) > 
+          (h[i] - h[i-1]).cross(h[j] - h[i-1]))
+        j = j % n + 1;
+
+      ans = max(ans, dist(h[j], h[i]));
+      ans = max(ans, dist(h[j], h[i-1]));
+    }
+
+    return ans;
+  }
+};
diff --git a/algorithms/geometry/primitives.cpp b/algorithms/geometry/primitives.cpp
new file mode 100644
index 0000000..51cee51
--- /dev/null
+++ b/algorithms/geometry/primitives.cpp
@@ -0,0 +1,8 @@
+/// Geometry Primitives
+
+#define to_deg(x) ((x * 180.0) / M_PI)
+#define to_rad(x) ((x * M_PI) / 180.0)
+
+double dist(Point<> a, Point<> b) {
+  return hypot(a.x - b.x, a.y - b.y);
+}
diff --git a/algorithms/geometry/rotating_calipers.cpp b/algorithms/geometry/rotating_calipers.cpp
deleted file mode 100644
index 65fd15e..0000000
--- a/algorithms/geometry/rotating_calipers.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/// Rotating Calipers
-///
-/// Time: O(n log n)
-/// Space: O(n)
-
-double dist(point a, point b) {
-  return hypot(a.fi - b.fi, a.se - b.se);
-}
-
-double area(point a, point b, point c) {
-  return abs((b.fi - a.fi) * (c.se - a.se) - \
-             (b.se - a.se) * (c.fi - a.fi));
-}
-
-double diameter(vector<point> &v) {
-  vector<point> h = convex_hull(v);
-
-  int m = h.size();
-  if (m == 1) return 0;
-  if (m == 2) return dist(h[0], h[1]);
-
-  int k = 1;
-  while (area(h[m-1], h[0], h[(k+1)%m]) > 
-         area(h[m-1], h[0], h[k]))
-    k++;
-
-  double ans = 0;
-  for (int i = 0, j = k; i <= k && j < m; ++i) {
-    ans = max(ans, dist(h[i], h[j]));
-
-    while (i < m && 
-        area(h[i], h[(i+1)%m], h[(j+1)%m]) > 
-        area(h[i], h[(i+1)%m], h[j])) 
-    {
-      ans = max(ans, dist(h[i], h[(j+1)%m]));
-      j++;
-    }
-  }
-
-  return ans;
-}
diff --git a/algorithms/geometry/segment.cpp b/algorithms/geometry/segment.cpp
new file mode 100644
index 0000000..aaf4d97
--- /dev/null
+++ b/algorithms/geometry/segment.cpp
@@ -0,0 +1,48 @@
+/// Segment
+
+template <typename T = double>
+struct Segment {
+  Point<T> a, b;
+
+  Segment(Point<T> a, Point<T> b) : a(a), b(b) {}
+
+  // Checks if points p and q are on the same side 
+  // of the segment.
+  bool same_side(Point<T> p, Point<T> q) { 
+    T cpp = (p - a).cross(b - a);
+    T cpq = (q - a).cross(b - a);
+    return ((cpp > 0 && cpq > 0) || 
+        (cpp < 0 && cpq < 0));
+  }
+
+  // Checks if point p is on the segment.
+  bool on_segment(Point<T> p) {
+    return (p.x <= max(a.x, b.x) && 
+        p.x >= min(a.x, b.x) &&
+        p.y <= max(a.y, b.y) && 
+        p.y >= min(a.y, b.y));
+  }
+
+  // Distance between segment and point
+  double dist(Point<T> p) {
+    return (a - b).cross(p - b)/sqrt((b - a).dot(b - a));
+  }
+
+  // Checks if segment intersects with s.
+  bool intersect(Segment<T> s) {
+    int o1 = Point<>::orientation(  a,   b, s.a);
+    int o2 = Point<>::orientation(  a,   b, s.b);
+    int o3 = Point<>::orientation(s.a, s.b,   a);
+    int o4 = Point<>::orientation(s.a, s.b,   b);
+
+    if (o1 != o2 && o3 != o4)
+      return true;
+
+    if (o1 == 0 && on_segment(s.a)) return true;
+    if (o2 == 0 && on_segment(s.b)) return true;
+    if (o3 == 0 && s.on_segment(a)) return true;
+    if (o4 == 0 && s.on_segment(b)) return true;
+
+    return false;
+  }
+};
diff --git a/contests/Cadernaveis/LA5138.cpp b/contests/Cadernaveis/LA5138.cpp
index 732fc82..fb0707b 100644
--- a/contests/Cadernaveis/LA5138.cpp
+++ b/contests/Cadernaveis/LA5138.cpp
@@ -19,27 +19,42 @@ using namespace std;
 using ll = long long;
 using ii = pair<int,int>;
 
-using point = pair<double,double>;
+template <typename T = double>
+struct Point {
+  T x, y; 
 
-bool cw(point a, point b, point c) {
-  return (b.fi - a.fi) * (c.se - a.se) - \
-    (b.se - a.se) * (c.fi - a.fi) <= 0;
-}
+  Point() {}
+  Point(T x, T y) : x(x), y(y) {}
+
+  Point operator+(Point p) { return Point(x+p.x, y+p.y); }
+  Point operator-(Point p) { return Point(x-p.x, y-p.y); }
+  Point operator*(T s) { return Point(x*s, y*s); }
+
+  T dot(Point p)   { return (x*p.x) + (y*p.y); }
+  T cross(Point p) { return (x*p.y) - (y*p.x); }
+};
 
-//double cross(point a, point b, point c) {
-//  return (b.fi - a.fi) * (c.se - a.se) - \
-//    (b.se - a.se) * (c.fi - a.fi);
-//}
-double cross(const point &o, const point &a, const point &b) {
-  return (a.fi - o.fi) * (b.se - o.se) - (a.se - o.se) * (b.fi - o.fi);
+bool cw(Point<> a, Point<> b, Point<> c) {
+  return (b - a).cross(c - a) <= 0;
 }
 
-vector<point> convex_hull(vector<point> &v) {
+template <typename T = double>
+struct Segment {
+  Point<T> a, b;
+
+  Segment(Point<T> a, Point<T> b) : a(a), b(b) {}
+
+  double dist(Point<T> p) {
+    return (a - b).cross(p - b)/sqrt((b - a).dot(b - a));
+  }
+};
+
+vector<Point<>> convex_hull(vector<Point<>> &v) {
   int k = 0;
-  vector<point> ans(v.size() * 2);
+  vector<Point<>> ans(v.size() * 2);
 
-  sort(all(v), [](const point &a, const point &b) {
-    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+  sort(all(v), [](const Point<> &a, const Point<> &b) {
+    return (a.x == b.x) ? (a.y < b.y) : (a.x < b.x);
   });
 
   for (int i = 0; i < v.size(); ++i) {
@@ -56,21 +71,20 @@ vector<point> convex_hull(vector<point> &v) {
   return ans;
 }
 
-double dist_line(point p, point a, point b) {
-  return cross(b, a, p) / sqrt((b.se-a.se) * (b.se-a.se) + (b.fi-a.fi)*(b.fi-a.fi));
-}
+double width(vector<Point<>> &v) {
+  vector<Point<>> h = convex_hull(v);
 
-double width(vector<point> &v) {
-  vector<point> h = convex_hull(v);
   int n = h.size() - 1;
-  int j = 1;
-
   double ans = 1e14;
+
   h[0] = h[n];
-  for (int i = 1; i <= n; ++i) {
-    while (cross(h[i-1], h[i], h[j%n+1]) > cross(h[i-1], h[i], h[j]))
+  for (int i = 1, j = 1; i <= n; ++i) {
+    while ((h[i] - h[i-1]).cross(h[j%n+1] - h[i-1]) > 
+           (h[i] - h[i-1]).cross(h[j] - h[i-1]))
       j = j % n + 1;
-    ans = min(ans, dist_line(h[j], h[i], h[i-1]));
+
+    Segment<> seg(h[i], h[i-1]);
+    ans = min(ans, seg.dist(h[j]));
   }
 
   return ceil(ans*100)/100;
@@ -83,9 +97,9 @@ int main() {
 
   int n, cas = 1;
   while (cin >> n && n) {
-    vector<point> v(n);
+    vector<Point<>> v(n);
     for (int i = 0; i < n; ++i)
-      cin >> v[i].fi >> v[i].se;
+      cin >> v[i].x >> v[i].y;
 
     cout << "Case " << cas << ": " << width(v) << ende;
     cas++;
diff --git a/contests/SBC15/A.cpp b/contests/SBC15/A.cpp
new file mode 100644
index 0000000..e2a4903
--- /dev/null
+++ b/contests/SBC15/A.cpp
@@ -0,0 +1,65 @@
+#include <bits/stdc++.h>
+
+#define MAX 10101
+#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<ii> graph[MAX];
+vector<ii> gg[MAX];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int c, v; cin >> c >> v;
+  for (int i = 0; i < v; ++i) {
+    int a, b, w; cin >> a >> b >> w;
+    graph[a].pb({b, w});
+    graph[b].pb({a, w});
+  }
+
+  for (int i = 1; i <= c; ++i)
+    for (auto j : graph[i])
+      for (auto k : graph[j.fi])
+        gg[i].pb({k.fi, j.se + k.se});
+
+  vector<int> vis(c + 1, 0);
+  vector<int> dist(c + 1, inf);
+
+  set<ii> pq;
+  pq.insert({0, 1});
+  dist[1] = 0;
+  while (!pq.empty()) {
+    int u = pq.begin()->se;
+    pq.erase(pq.begin());
+
+    if (vis[u]) continue;
+    vis[u] = 1;
+
+    for (auto i : gg[u])
+      if (!vis[i.fi] && dist[i.fi] > dist[u] + i.se) {
+        dist[i.fi] = dist[u] + i.se;
+        pq.insert({dist[i.fi], i.fi});
+      }
+  }
+
+  if (dist[c] == inf) dist[c] = -1;
+  cout << dist[c] << ende;
+  return 0;
+}
diff --git a/contests/SBC15/B.cpp b/contests/SBC15/B.cpp
new file mode 100644
index 0000000..b0f5abd
--- /dev/null
+++ b/contests/SBC15/B.cpp
@@ -0,0 +1,40 @@
+#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; cin >> n >> c;
+  vector<int> v(n);
+  vector<vector<int>> dp(n, vector<int>(2));
+
+  for (auto &i : v) cin >> i;
+
+  dp[n-1] = {0, v[n-1]};
+  for (int i = n - 2; i >= 0; --i) {
+    dp[i][1] = max(dp[i + 1][0] + v[i], dp[i + 1][1]);    
+    dp[i][0] = max(dp[i + 1][0], dp[i + 1][1] - (v[i] + c));
+  }
+
+  cout << max(0, dp[0][0]) << ende;
+  return 0;
+}
diff --git a/contests/SBC15/C.cpp b/contests/SBC15/C.cpp
new file mode 100644
index 0000000..ee90cb2
--- /dev/null
+++ b/contests/SBC15/C.cpp
@@ -0,0 +1,30 @@
+#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 a, b; cin >> a >> b;
+  cout << max(a, b) << ende;
+
+  return 0;
+}
diff --git a/contests/SBC15/D.cpp b/contests/SBC15/D.cpp
new file mode 100644
index 0000000..13a3552
--- /dev/null
+++ b/contests/SBC15/D.cpp
@@ -0,0 +1,92 @@
+#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 c[101], r[101];
+string mat[101][101];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, m; cin >> n >> m;
+
+  int k = 0;
+  map<string,int> M;
+  for (int i = 0; i < n; ++i) {
+    for (int j = 0; j < m; ++j) {
+      cin >> mat[i][j];
+      M[mat[i][j]] = k++;
+    }
+    cin >> c[i];
+  }
+
+  for (int j = 0; j < m; ++j)
+    cin >> r[j];
+
+  map<string,int> ans;
+  for (int i = 0; i < M.size(); ++i) {
+    string found = "nono";
+
+    for (int j = 0; j < n; ++j) {
+      map<string,int> S;
+      for (int k = 0; k < m; ++k) 
+        S[mat[j][k]]++;
+
+      if (S.find("aaa") != S.end())
+        S.erase("aaa");
+
+      if (S.size() == 1) {
+        found = S.begin()->fi;
+        ans[S.begin()->fi] = c[j] / S.begin()->se;
+        break;
+      }
+    }
+
+    if (found == "nono") {
+      for (int j = 0; j < m; ++j) {
+        map<string,int> S;
+        for (int k = 0; k < n; ++k) 
+          S[mat[k][j]]++;
+
+        if (S.find("aaa") != S.end())
+          S.erase("aaa");
+
+        if (S.size() == 1) {
+          found = S.begin()->fi;
+          ans[S.begin()->fi] = r[j] / S.begin()->se;
+          break;
+        }
+      }
+    }
+
+    for (int j = 0; j < n; ++j)
+      for (int k = 0; k < m; ++k)
+        if (mat[j][k] == found) {
+          r[k] -= ans[found];
+          c[j] -= ans[found];
+          mat[j][k] = "aaa";
+        }
+  }
+
+  for (auto i : ans)
+    cout << i.fi << " " << i.se << ende;
+  return 0;
+}
diff --git a/contests/SBC15/E.cpp b/contests/SBC15/E.cpp
new file mode 100644
index 0000000..ffb2680
--- /dev/null
+++ b/contests/SBC15/E.cpp
@@ -0,0 +1,52 @@
+#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);
+
+  ll n, b; cin >> n >> b;
+  if (b <= n)
+    return cout << 1 << " " << b, 0;
+
+  auto f = [&](ll x) {
+    ll sum = ((n - 1LL) * n);
+    return sum - (x * (x+1LL));
+  };
+
+  ll k = n - 1;
+  for (ll bb = n / 2; bb >= 1; bb /= 2)
+    while (k - bb >= 0 && n + f(k - bb) <= b)
+      k -= bb;
+
+  ll base = n + f(k);
+  if (base + k <= b)
+    base += k;
+
+  ll kk = 0;
+  for (ll bb = n / 2; bb >= 1; bb /= 2)
+    while (base + kk + bb < )
+
+  cout << f(6) << ende;
+  cout << k << ende;
+  cout << base << ende;
+  return 0;
+}
diff --git a/contests/SBC15/F.cpp b/contests/SBC15/F.cpp
new file mode 100644
index 0000000..3f7986e
--- /dev/null
+++ b/contests/SBC15/F.cpp
@@ -0,0 +1,41 @@
+#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;
+  vector<int> fat(10);
+  fat[0] = 1;
+  for (int i = 1; i < 10; ++i)
+    fat[i] = fat[i-1] * i;
+
+  int ans = 0;
+  for (int i = 9; i >= 1; --i)
+    while (n - fat[i] >= 0) {
+      n -= fat[i];
+      ans++;
+    }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/SBC15/J.cpp b/contests/SBC15/J.cpp
new file mode 100644
index 0000000..f463b2f
--- /dev/null
+++ b/contests/SBC15/J.cpp
@@ -0,0 +1,40 @@
+#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 j, r; cin >> j >> r;
+  vector<int> p(j, 0);
+  for (int i = 0; i < j*r; ++i) {
+    int x; cin >> x;
+    p[i%j] += x;
+  }
+
+  int ans = 0;
+  for (int i = 0; i < j; ++i)
+    if (p[ans] <= p[i])
+      ans = i;
+
+  cout << ans + 1 << ende;
+  return 0;
+}
diff --git a/contests/SBC15/K.cpp b/contests/SBC15/K.cpp
new file mode 100644
index 0000000..0735dbf
--- /dev/null
+++ b/contests/SBC15/K.cpp
@@ -0,0 +1,67 @@
+#include <bits/stdc++.h>
+
+#define MAX 2010
+#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 n;
+string s;
+int v[MAX];
+ii dp[MAX][MAX];
+
+ii operator+(const ii &a, const ii &b) {
+  return {a.fi + b.fi, a.se + b.se};
+}
+
+ii solve(int l, int r) {
+  if (l > r)  return ii(0, 0);
+  if (l == r) return ii(v[l], 1);
+
+  if (dp[l][r].fi != -1)
+    return dp[l][r];
+
+  ii op = {-inf, -inf};
+  if (s[l] == s[r])
+    op = solve(l + 1, r - 1) + ii(v[l] + v[r], 2);
+
+  return dp[l][r] = max({
+      op,
+      solve(l + 1, r - 1),
+      solve(l + 1, r),
+      solve(l, r - 1)
+  });
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  cin >> s >> n;
+  for (int i = 0; i < n; ++i) {
+    int x; cin >> x;
+    v[x - 1] = 1;
+  }
+
+  for (int i = 0; i < MAX; ++i)
+    for (int j = 0; j < MAX; ++j)
+      dp[i][j] = {-1, -1};
+
+  cout << solve(0, s.size() - 1).se << ende; 
+  return 0;
+}
-- 
GitLab