#include <bits/stdc++.h>
using namespace std;
struct state {
  int len, link;
  map<char, int> next;
};
const int MAXLEN = 400500;
state st[MAXLEN];
int sz, last;
int pos[MAXLEN];
int lefto[9000000], righto[9000000], nw;
void sa_init() {
  sz = last = 0;
  st[0].len = 0;
  st[0].link = -1;
  ++sz;
}
void sa_extend(char c, int indx) {
  int cur = sz++;
  pos[cur] = indx;
  st[cur].len = st[last].len + 1;
  int p;
  for (p = last; p != -1 && !st[p].next.count(c); p = st[p].link)
    st[p].next[c] = cur;
  if (p == -1)
    st[cur].link = 0;
  else {
    int q = st[p].next[c];
    if (st[p].len + 1 == st[q].len)
      st[cur].link = q;
    else {
      int clone = sz++;
      st[clone].len = st[p].len + 1;
      st[clone].next = st[q].next;
      st[clone].link = st[q].link;
      pos[clone] = pos[q];
      for (; p != -1 && st[p].next[c] == q; p = st[p].link)
        st[p].next[c] = clone;
      st[q].link = st[cur].link = clone;
    }
  }
  last = cur;
}
char str[300000];
bool query(int node, int st, int en, int l, int r) {
  if (!node) return 0;
  if (st > r or en < l) return 0;
  if (st >= l and en <= r) return 1;
  int mid = (st + en) >> 1;
  bool g = query(lefto[node], st, mid, l, r);
  if (g) return 1;
  return query(righto[node], mid + 1, en, l, r);
}
int update(int node, int st, int en, int l) {
  if (st > l or en < l) return node;
  int ps = ++nw;
  if (st == en) {
    return ps;
  }
  int mid = (st + en) >> 1;
  lefto[ps] = update(lefto[node], st, mid, l);
  righto[ps] = update(righto[node], mid + 1, en, l);
  return ps;
}
int root[MAXLEN];
int mergee(int node, int node2, int st, int en) {
  if (node == 0 || node2 == 0) return node ^ node2;
  int ps = ++nw;
  if (st == en) {
    return ps;
  }
  int mid = (st + en) >> 1;
  lefto[ps] = mergee(lefto[node], lefto[node2], st, mid);
  righto[ps] = mergee(righto[node], righto[node2], mid + 1, en);
  return ps;
}
vector<pair<int, int> > vc;
int dp[MAXLEN], par[MAXLEN];
int main() {
  int i, j, k, l, m, n;
  scanf("%d", &n);
  scanf("%s", str + 1);
  sa_init();
  for (int i = 1; str[i]; i++) {
    sa_extend(str[i], i);
    root[last] = update(0, 1, n, i);
  }
  for (int i = 1; i < sz; i++) {
    vc.push_back(make_pair(st[i].len, i));
  }
  sort(vc.begin(), vc.end());
  for (int i = vc.size() - 1; i >= 0; i--) {
    int w = vc[i].second;
    if (st[w].link <= 0) continue;
    root[st[w].link] = mergee(root[st[w].link], root[w], 1, n);
  }
  for (int i = 0; i < vc.size(); i++) {
    int w = vc[i].second;
    int p = st[w].link;
    if (p <= 0) {
      dp[w] = 1;
      par[w] = w;
      continue;
    }
    int f = par[p];
    int g = query(root[f], 1, n, pos[w] - st[w].len + st[f].len, pos[w] - 1);
    if (g == 0) {
      dp[w] = dp[p];
      par[w] = f;
    } else {
      dp[w] = dp[f] + 1;
      par[w] = w;
    }
  }
  int ma = 0;
  for (int i = 1; i < sz; i++) {
    ma = max(ma, dp[i]);
  }
  cout << ma << endl;
}
