We call a sequence of strings t1, ..., tk a journey of length k, if for each i > 1 ti is a substring of ti - 1 and length of ti is strictly less than length of ti - 1. For example, {ab, b} is a journey, but {ab, c} and {a, a} are not.

Define a journey on string s as journey t1, ..., tk, such that all its parts can be nested inside s in such a way that there exists a sequence of strings u1, ..., uk + 1 (each of these strings can be empty) and s = u1 t1 u2 t2... uk tk uk + 1. As an example, {ab, b} is a journey on string abb, but not on bab because the journey strings ti should appear from the left to the right.

The length of a journey on a string is the number of strings in it. Determine the maximum possible length of a journey on the given string s.

Input

The first line contains a single integer n (1 ≤ n ≤ 500 000) — the length of string s.

The second line contains the string s itself, consisting of n lowercase Latin letters.

Output

Print one number — the maximum possible length of string journey on s.

Examples

Input

7
abcdbcc


Output

3


Input

4
bbcb


Output

2

Note

In the first sample, the string journey of maximum length is {abcd, bc, c}.

In the second sample, one of the suitable journeys is {bb, b}.
#include <bits/stdc++.h>
template <class __TyFirst, class __TySecond>
std::ostream& operator<<(std::ostream& out,
                         const std::pair<__TyFirst, __TySecond>& o) {
  out << "(" << o.first << "," << o.second << ")";
  return out;
}
template <typename _ForwardIterator>
void logArray(_ForwardIterator __begin, _ForwardIterator __end,
              const char* __sep = 0) {}
template <class T>
inline bool checkMin(T& a, T b) {
  return (a > b ? a = b, 1 : 0);
}
template <class T>
inline bool checkMax(T& a, T b) {
  return (a < b ? a = b, 1 : 0);
}
void preInit();
void init();
void solve();
int32_t main() {
  preInit();
  init();
  solve();
  return 0;
}
constexpr int N = 500005;
constexpr int B = 20;
constexpr int C = 26;
struct SAM {
  struct Node {
    int link = -1, next[C], len = 0;
    std::vector<int> e;
    int fa[B], dl, dr;
    Node() { memset(next, -1, sizeof(next)); }
  } p[N * 2];
  static constexpr int root = 0;
  int last = root, cnt = last + 1, dfn = 0;
  int pos[N], pos_top = 0;
  void insert(std::size_t c) {
    int cur = pos[pos_top++] = cnt++;
    p[cur].len = p[last].len + 1;
    int pos = last;
    while (pos != -1 && p[pos].next[c] == -1) {
      p[pos].next[c] = cur;
      pos = p[pos].link;
    }
    if (pos == -1) {
      p[cur].link = root;
    } else {
      int q = p[pos].next[c];
      if (p[q].len == p[pos].len + 1) {
        p[cur].link = q;
      } else {
        int clone = cnt++;
        p[clone] = p[q];
        p[clone].len = p[pos].len + 1;
        p[q].link = p[cur].link = clone;
        while (pos != -1 && p[pos].next[c] == q) {
          p[pos].next[c] = clone;
          pos = p[pos].link;
        }
      }
    }
    last = cur;
  }
  void build() {
    for (int i = 1; i <= cnt - 1; i++) p[p[i].link].e.push_back(i);
  }
  void dfs(int u = root) {
    p[u].dl = dfn++;
    p[u].fa[0] = p[u].link;
    for (int i = 0; i < B - 1; i++)
      if (p[u].fa[i] != -1) {
        p[u].fa[i + 1] = p[p[u].fa[i]].fa[i];
      }
    for (int v : p[u].e) {
      dfs(v);
    }
    p[u].dr = dfn - 1;
  }
  int jump(int pos, int len) {
    for (int i = B - 1; i >= 0; i--)
      if (p[pos].fa[i] != -1 && p[p[pos].fa[i]].len >= len) {
        pos = p[pos].fa[i];
      }
    return pos;
  }
} SAM;
struct STree {
 public:
  void init(int l, int r) {
    g_l = l;
    g_r = r;
  }
  void modify(int pos, int val) { __modify(g_l, g_r, pos, val, root); }
  int query(int l, int r) { return __query(l, r, g_l, g_r, root); }

 private:
  struct Node {
    int val;
    void pushUp(const Node& a, const Node& b) { val = std::max(a.val, b.val); }
  } p[N * 8];
  static constexpr int root = 1;
  int g_l, g_r;
  void __modify(int l, int r, int pos, int val, int u) {
    if (l == r) {
      p[u].val = val;
      return;
    }
    int mid = (l + r) / 2;
    if (pos <= mid) {
      __modify(l, mid, pos, val, u + u);
    } else {
      __modify(mid + 1, r, pos, val, u + u + 1);
    }
    p[u].pushUp(p[u + u], p[u + u + 1]);
  }
  int __query(int sl, int sr, int l, int r, int u) {
    if (sl <= l && r <= sr) {
      return p[u].val;
    }
    int mid = (l + r) / 2;
    if (sr <= mid) {
      return __query(sl, sr, l, mid, u + u);
    }
    if (sl > mid) {
      return __query(sl, sr, mid + 1, r, u + u + 1);
    }
    return std::max(__query(sl, sr, l, mid, u + u),
                    __query(sl, sr, mid + 1, r, u + u + 1));
  }
} St;
char s[N];
int dp[N], n;
void preInit() {}
void init() {
  scanf("%d", &n);
  scanf("%s", s);
  std::reverse(s, s + n);
  for (int i = 0; i < n; i++) SAM.insert(s[i] - 'a');
  SAM.build();
  SAM.dfs();
  St.init(0, SAM.cnt - 1);
}
void solve() {
  ;
  dp[0] = 1;
  int left = 0;
  auto check = [](int pos, int len) {
    int pos0 = SAM.jump(SAM.pos[pos - 1], len - 1);
    int pos1 = SAM.jump(SAM.pos[pos], len - 1);
    return St.query(SAM.p[pos0].dl, SAM.p[pos0].dr) + 1 >= len ||
           St.query(SAM.p[pos1].dl, SAM.p[pos1].dr) + 1 >= len;
  };
  for (int i = 1; i <= n - 1; i++) {
    dp[i] = dp[i - 1] + 1;
    while (!check(i, dp[i])) {
      dp[i]--;
      St.modify(SAM.p[SAM.pos[left]].dl, dp[left]);
      left++;
    }
  }
  logArray(dp, dp + n);
  printf("%d\n", *std::max_element(dp, dp + n));
}
