#include <bits/stdc++.h>   const int MAXN = 4e5 + 5, MAXLOG = 20, MAXS = MAXN * 50;   template <typename _T>   void read(_T &x) {     x = 0;     char s = getchar();     int f = 1;     while (s >  9  || s <  0 ) {       if (s ==  - ) f = -1;       s = getchar();     }     while (s >=  0  && s <=  9 ) {       x = (x << 3) + (x << 1) + (s -  0 ), s = getchar();     }     x *= f;   }   template <typename _T>   void write(_T x) {     if (x < 0) {       putchar( - );       x = (~x) + 1;     }     if (9 < x) {       write(x / 10);     }     putchar(x % 10 +  0 );   }   template <typename _T>   _T MAX(const _T a, const _T b) {     return a > b ? a : b;   }   template <typename _T>   _T MIN(const _T a, const _T b) {     return a < b ? a : b;   }   struct edge {     int to, nxt;   } Graph[MAXN << 1];   int f[MAXN][MAXLOG];   bool s[MAXS];   int lch[MAXS], rch[MAXS];   int dp[MAXN], seq[MAXN], ID;   int ch[MAXN][26], fa[MAXN], mx[MAXN], head[MAXN], rot[MAXN], fir[MAXN];   int N, lg2, rt, lst, tot, cnt, siz;   char S[MAXN];   void upt(const int x) { s[x] = s[lch[x]] | s[rch[x]]; }   void copy(int a, int b) {     fa[a] = fa[b], mx[a] = mx[b], memcpy(ch[a], ch[b], sizeof ch[b]);   }   void addEdge(const int from, const int to) {     Graph[++cnt].to = to, Graph[cnt].nxt = head[from];     head[from] = cnt;   }   void expand(const char c) {     int x = c -  a , p = lst, cur = ++tot;     mx[cur] = mx[lst] + 1, lst = cur;     while (p && !ch[p][x]) ch[p][x] = cur, p = fa[p];     if (!p) {       fa[cur] = rt;       return;     }     int q = ch[p][x];     if (mx[q] == mx[p] + 1) {       fa[cur] = q;       return;     }     int nq = ++tot;     copy(nq, q);     mx[nq] = mx[p] + 1, fa[q] = fa[cur] = nq;     while (p && ch[p][x] == q) ch[p][x] = nq, p = fa[p];   }   void update(int &u, const int l, const int r, const int pos) {     if (!u) u = ++siz;     if (l == r) {       s[u] = true;       return;     }     int mid = l + r >> 1;     if (pos <= mid)       update(lch[u], l, mid, pos);     else       update(rch[u], mid + 1, r, pos);     upt(u);   }   bool query(const int u, const int l, const int r, const int segL,              const int segR) {     if (!u) return false;     if (segL <= l && r <= segR) return s[u];     int mid = l + r >> 1, ret = false;     if (segL <= mid) ret |= query(lch[u], l, mid, segL, segR);     if (mid < segR) ret |= query(rch[u], mid + 1, r, segL, segR);     return ret;   }   int merg(int u, int v) {     if (!u || !v) return u + v;     int cur = ++siz;     lch[cur] = merg(lch[u], lch[v]);     rch[cur] = merg(rch[u], rch[v]);     s[cur] = s[u] | s[v];     return cur;   }   void DFS(const int u) {     seq[++ID] = u;     for (int i = head[u], v; i; i = Graph[i].nxt) {       DFS(v = Graph[i].to);       rot[u] = merg(rot[u], rot[v]);       fir[u] = MIN(fir[u], fir[v]);     }   }   int main() {     rt = lst = ++tot;     memset(fir, 0x3f, sizeof fir);     read(N), scanf( %s , S + 1);     for (int i = 1; i <= N; i++)       expand(S[i]), update(rot[lst], 1, N, i), fir[lst] = i;     for (int i = 2; i <= tot; i++) addEdge(fa[i], i);     DFS(rt);     lg2 = log2(tot);     for (int i = 1; i <= tot; i++) f[i][0] = fa[i];     for (int j = 1; j <= lg2; j++)       for (int i = 1; i <= tot; i++) f[i][j] = f[f[i][j - 1]][j - 1];     for (int i = tot, u, p; i; i--) {       u = p = seq[i];       for (int k = lg2; ~k; k--)         if (f[p][k] > rt &&             !query(rot[f[p][k]], 1, N, fir[u] - mx[u] + mx[f[p][k]], fir[u] - 1))           p = f[p][k];       p = fa[p];       dp[p] = MAX(dp[p], dp[u] + 1);     }     write(dp[rt]), putchar(  n );     return 0;   }