diff --git a/day 12/day_12_max_n.cpp b/day 12/day_12_max_n.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a8163ab2042658a4b68e892da43296ae5f2f8c98
--- /dev/null
+++ b/day 12/day_12_max_n.cpp	
@@ -0,0 +1,125 @@
+#include <bits/stdc++.h>
+
+#ifdef LOCAL
+#include "./cpp-dump/cpp-dump.hpp"
+#define pr(x) cpp_dump(x)
+#endif
+
+using namespace std;
+
+#define Mod(x,y) (((x)%(y)+(y))%(y))
+#define rep(i, a, b) for(ll (i) = (a); (i) < (b); ++(i))
+#define all(x) begin(x), end(x)
+#define pb push_back
+#define gcd __gcd 
+#define sz(x) (ll)(x.size())
+
+typedef long long ll;
+typedef unsigned long long ull;
+typedef pair<ll, ll> pii;
+typedef vector<ll> vi;
+typedef vector<pii> vii;
+
+struct UF {
+    vi e;
+    UF(int n) : e(n, -1) {}
+    bool sameSet(int a, int b) { return find(a) == find(b); }
+    int size(int x) { return -e[find(x)]; }
+    int find(int x) { return e[x] < 0 ? x : e[x] = find(e[x]); }
+    bool join(int a, int b) {
+        a = find(a), b = find(b);
+        if (a == b) return false;
+        if (e[a] > e[b]) swap(a, b);
+        e[a] += e[b]; e[b] = a;
+        return true;
+    }
+};
+
+const int mxn = 20000;
+struct UF uf(mxn);
+
+vector<string> vs;
+int n, m;
+
+int to_int(int a, int b) { return a*m+b; }
+
+map<int, int> area, boundary;
+
+bool the_same(int i, int j, int di, int dj) { // 0 same set
+    int ni = i+di, nj = j+dj;
+    if (min(ni, nj) >= 0 && ni < n && nj < m && uf.sameSet(to_int(i, j), to_int(ni, nj))) 
+        return true;
+    return false;
+}
+
+
+int on_boundary_part1(int i, int j) {
+    int ret = !the_same(i, j, -1, 0);
+    ret += !the_same(i, j, 1, 0);
+    ret += !the_same(i, j, 0, -1);
+    ret += !the_same(i, j, 0, 1);
+    return ret;
+}
+
+int on_boundary_part2(int i, int j) {
+    int ret = 0;
+    // looking up
+    if (!the_same(i, j, -1, 0)) {
+        if (!the_same(i, j, 0, -1) || the_same(i, j-1, -1, 0)) ret++;
+    }
+    // looking left
+    if (!the_same(i, j, 0, -1)) {
+        if (!the_same(i, j, 1, 0) || the_same(i+1, j, 0, -1)) ret++;
+    }
+    // looking down
+    if (!the_same(i, j, 1, 0)) {
+        if (!the_same(i, j, 0, 1) || the_same(i, j+1, 1, 0)) ret++;
+    }
+    // looking right
+    if (!the_same(i, j, 0, 1)) {
+        if (!the_same(i, j, -1, 0) || the_same(i-1, j, 0, 1)) ret++;
+    }
+    return ret;
+}
+
+void solve() {
+    string s;
+    while(cin >> s) vs.pb(s);
+    n = vs.size();
+    m = vs[0].size();
+
+    rep(i, 0, n) rep(j, 0, m) {
+        rep(di, -1, 2) rep(dj, -1, 2) if (di == 0 || dj == 0) {
+            int ni = i+di, nj = j+dj;
+            if (min(ni, nj) >= 0 && ni < n && nj < m) {
+                if (vs[i][j] == vs[ni][nj]) {
+                    uf.join(to_int(i, j), to_int(ni, nj));
+                }
+            }
+        }
+    }
+
+    bool PART1 = true;
+
+    rep(i, 0, n) rep(j, 0, m) {
+        int rep = uf.find(to_int(i, j));
+        area[rep]++;
+        boundary[rep] += (PART1 ? on_boundary_part1(i, j) : on_boundary_part2(i, j));
+    }
+
+    ll ans = 0;
+    for (auto p : area) ans += p.second*boundary[p.first];
+    pr(ans);
+} 
+
+
+int main() {
+    ios::sync_with_stdio(0);cin.tie(0);
+    cout << setprecision(15) << fixed;
+
+#ifdef LOCAL
+    freopen("input.txt", "r", stdin);
+#endif
+
+    solve();
+}