#include <bits/stdc++.h>
template <class T>
__inline__ __attribute__((always_inline)) bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}
template <class T>
__inline__ __attribute__((always_inline)) bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}
template <class T>
__inline__ __attribute__((always_inline)) T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}
template <class T>
__inline__ __attribute__((always_inline)) T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}
template <class T>
__inline__ __attribute__((always_inline)) T myabs(const T &a) {
  return a > 0 ? a : -a;
}
const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);
const int MAXN = 500000 + 5, LOG = 20 + 5;
char str[MAXN];
int lg[MAXN];
struct SuffixArray {
  char str[MAXN];
  int *tmp, *rk, c[MAXN], sa[MAXN], height[MAXN], st[LOG][MAXN];
  SuffixArray() {
    tmp = new int[MAXN];
    rk = new int[MAXN];
  }
  void build(int n, int m) {
    for (int i = (1), iend = (n); i <= iend; ++i) {
      ++c[rk[i] = str[i] - 'a' + 1];
    }
    for (int i = (2), iend = (m); i <= iend; ++i) {
      c[i] += c[i - 1];
    }
    for (int i = (n), iend = (1); i >= iend; --i) {
      sa[c[rk[i]]--] = i;
    }
    for (int k = 1; k <= n; k <<= 1) {
      int cnt = 0;
      for (int i = (n - k + 1), iend = (n); i <= iend; ++i) {
        tmp[++cnt] = i;
      }
      for (int i = (1), iend = (n); i <= iend; ++i) {
        if (sa[i] > k) {
          tmp[++cnt] = sa[i] - k;
        }
      }
      for (int i = (1), iend = (m); i <= iend; ++i) {
        c[i] = 0;
      }
      for (int i = (1), iend = (n); i <= iend; ++i) {
        ++c[rk[i]];
      }
      for (int i = (2), iend = (m); i <= iend; ++i) {
        c[i] += c[i - 1];
      }
      for (int i = (n), iend = (1); i >= iend; --i) {
        sa[c[rk[tmp[i]]]--] = tmp[i];
      }
      std::swap(rk, tmp);
      cnt = 0;
      rk[sa[1]] = ++cnt;
      for (int i = (2), iend = (n); i <= iend; ++i) {
        rk[sa[i]] = (tmp[sa[i - 1]] == tmp[sa[i]] &&
                     tmp[sa[i - 1] + k] == tmp[sa[i] + k])
                        ? cnt
                        : ++cnt;
      }
      if (cnt >= n) {
        break;
      }
      m = cnt;
    }
  }
  void init(int n) {
    int cur = 0;
    for (int i = (1), iend = (n); i <= iend; ++i) {
      if (rk[i] == 1) {
        continue;
      }
      if (cur) {
        --cur;
      }
      int t = sa[rk[i] - 1];
      while (t + cur <= n && i + cur <= n && str[t + cur] == str[i + cur]) {
        ++cur;
      }
      height[rk[i]] = cur;
    }
    for (int i = (1), iend = (n); i <= iend; ++i) {
      st[0][i] = height[i];
    }
    for (int i = (1), iend = (lg[n]); i <= iend; ++i) {
      for (int j = (1), jend = (n - (1 << i) + 1); j <= jend; ++j) {
        st[i][j] = mymin(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
      }
    }
  }
  int LCP(int i, int j) {
    ++i;
    int t = lg[j - i + 1];
    return mymin(st[t][i], st[t][j - (1 << t) + 1]);
  }
} sa;
struct SegmentTree {
  int max[MAXN * 4], m;
  void build(int n) {
    for (m = 1; m < n; m <<= 1)
      ;
  }
  void modify(int p, int x) {
    max[p += m] = x;
    for (p >>= 1; p; p >>= 1) {
      max[p] = mymax(max[p << 1], max[p << 1 | 1]);
    }
  }
  int query(int l, int r) {
    int ret = 0;
    for (l += m - 1, r += m + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
      if (~l & 1) {
        chkmax(ret, max[l ^ 1]);
      }
      if (r & 1) {
        chkmax(ret, max[r ^ 1]);
      }
    }
    return ret;
  }
} seg;
int f[MAXN], n;
__inline__ __attribute__((always_inline)) bool check(int pos, int g) {
  int l = 1, r = sa.rk[pos] - 1, left = sa.rk[pos], right = sa.rk[pos];
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (sa.LCP(mid, sa.rk[pos]) >= g) {
      r = mid - 1, left = mid;
    } else {
      l = mid + 1;
    }
  }
  l = sa.rk[pos] + 1, r = n;
  while (l <= r) {
    int mid = (l + r) >> 1;
    if (sa.LCP(sa.rk[pos], mid) >= g) {
      l = mid + 1, right = mid;
    } else {
      r = mid - 1;
    }
  }
  return seg.query(left, right) >= g;
}
int main() {
  scanf("%d", &n);
  scanf("%s", str + 1);
  seg.build(n);
  strcpy(sa.str + 1, str + 1);
  sa.build(n, 26);
  lg[0] = -1;
  for (int i = (1), iend = (n); i <= iend; ++i) {
    lg[i] = lg[i >> 1] + 1;
  }
  sa.init(n);
  int cur = n + 1, ans = 0;
  for (int i = (n), iend = (1); i >= iend; --i) {
    int p = f[i + 1] + 1;
    for (; p > 1; --p) {
      if (chkmin(cur, i + p)) {
        seg.modify(sa.rk[cur], f[cur]);
      }
      if (check(i, p - 1) || check(i + 1, p - 1)) {
        break;
      }
    }
    f[i] = p;
    chkmax(ans, f[i]);
  }
  printf("%d\n", ans);
  return 0;
}
