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>
#pragma GCC optimize("Ofast")
using namespace std;
const long long MXN = 5e5 + 10;
const long long MXS = MXN * 4;
const long long LOG = 20;
long long n, pw;
string s;
long long rnk[MXN], SA[MXN], lcp[MXN], tmp[MXN];
long long lg[MXN], rmq[LOG][MXN], dp[MXN], seg[MXS];
inline bool CMP(long long i, long long j) {
  if (rnk[i] != rnk[j]) return (rnk[i] < rnk[j]);
  i += (1LL << (pw - 1)), j += (1LL << (pw - 1));
  if (i > n || j > n) return (i > j);
  return (rnk[i] < rnk[j]);
}
inline void BuildSuffixArray(const string &s) {
  assert((s[0] == '$') && (n + 1 == (int)s.size()));
  iota(SA + 1, SA + n + 1, 1), SA[0] = n + 1;
  for (int i = 1; i <= n; i++) rnk[i] = s[i];
  for (pw = 1; pw < LOG; pw++) {
    sort(SA + 1, SA + n + 1, CMP);
    for (int i = 2; i <= n; i++) {
      tmp[i] = tmp[i - 1] + CMP(SA[i - 1], SA[i]);
    }
    for (int i = 1; i <= n; i++) {
      rnk[SA[i]] = tmp[i];
    }
  }
  for (int i = 1; i <= n; i++) rnk[i]++;
}
inline void BuildLcpTable(const string &s) {
  assert((s[0] == '$') && (n + 1 == (int)s.size()));
  for (int i = 1, k = 0; i <= n; i++) {
    if (rnk[i] == n) continue;
    if (k) k--;
    while (s[i + k] == s[SA[rnk[i] + 1] + k]) {
      k++;
    }
    lcp[rnk[i] + 1] = k;
  }
}
inline void BuildRmqLcp() {
  for (int i = 0; (1LL << i) < MXN; i++) lg[(1LL << i)] = i;
  for (int i = 1; i < MXN; i++) lg[i] = max(lg[i - 1], lg[i]);
  for (int i = 1; i <= n; i++) rmq[0][i] = lcp[i];
  for (int j = 1; j < LOG; j++) {
    for (int i = 1; i <= n; i++) {
      if (i < (1LL << j)) continue;
      rmq[j][i] = min(rmq[j - 1][i], rmq[j - 1][i - (1LL << (j - 1))]);
    }
  }
}
void Upd(long long p, long long id = 1, long long s = 1, long long e = n) {
  if ((e - s + 1) == 1) {
    seg[id] = dp[SA[p]];
    return;
  }
  if (p <= ((s + e) / 2))
    Upd(p, (id * 2), s, ((s + e) / 2));
  else
    Upd(p, (id * 2 + 1), ((s + e) / 2 + 1), e);
  seg[id] = max(seg[(id * 2)], seg[(id * 2 + 1)]);
}
long long Get(long long l, long long r, long long id = 1, long long s = 1,
              long long e = n) {
  if (e < l || s > r) return 0;
  if (l <= s && e <= r) return seg[id];
  return max(Get(l, r, (id * 2), s, ((s + e) / 2)),
             Get(l, r, (id * 2 + 1), ((s + e) / 2 + 1), e));
}
bool check(long long p, long long t) {
  if (!t) return 1;
  long long l = rnk[p], r = rnk[p];
  for (int i = LOG - 1; ~i; i--) {
    if (r + (1LL << i) <= n && rmq[i][r + (1LL << i)] >= t) {
      r += (1LL << i);
    }
    if (l - (1LL << i) >= 1 && rmq[i][l] >= t) {
      l -= (1LL << i);
    }
  }
  return (Get(l, r) >= t);
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> s, s = "$" + s;
  BuildSuffixArray(s);
  BuildLcpTable(s);
  BuildRmqLcp();
  dp[n] = 1;
  for (int i = n - 1; i >= 1; i--) {
    dp[i] = dp[i + 1] + 1;
    while (!check(i + 1, dp[i] - 1) && !check(i, dp[i] - 1)) {
      dp[i]--, Upd(rnk[i + dp[i]]);
    }
  }
  cout << *max_element(dp + 1, dp + n + 1) << '\n';
  return 0;
}
