#line 1 "atcoder-workspace/abc141/e/e.cpp"
#include <iostream>
#include <string>
#include <unordered_map>

#line 2 "Library/string/rolling_hash.hpp"
#include <algorithm>
#include <cassert>
#include <vector>

#line 2 "Library/utils/random_number_generator.hpp"
#include <random>
template <typename num_type> class random_number_generator {
  typename std::conditional<std::is_integral<num_type>::value,
                            std::uniform_int_distribution<num_type>,
                            std::uniform_real_distribution<num_type>>::type
      unif;

  std::mt19937 engine;

 public:
  random_number_generator(num_type min = std::numeric_limits<num_type>::min(),
                          num_type max = std::numeric_limits<num_type>::max())
      : unif(min, max), engine(std::random_device{}()) {}

  num_type min() const { return unif.min(); }

  num_type max() const { return unif.max(); }

  // generate a random number in [min(), max()].
  num_type operator()() { return unif(engine); }
};
#line 7 "Library/string/rolling_hash.hpp"

struct rolling_hashed {
  using u64 = uint_least64_t;
  using u128 = __uint128_t;

  constexpr static u64 mod = (1ull << 61) - 1;
  static u64 base;

  u64 value = 0;
  size_t length = 0;

  operator std::pair<u64, size_t>() const { return {value, length}; }

  bool operator==(const rolling_hashed &rhs) const {
    return value == rhs.value && length == rhs.length;
  }

  rolling_hashed operator+(const rolling_hashed &rhs) const {
    return {plus(value, mult(rhs.value, base_pow(length))),
            length + rhs.length};
  }

  rolling_hashed operator-(const rolling_hashed &rhs) const {
    assert(!(length < rhs.length));
    return {minus(value, mult(rhs.value, base_pow(length - rhs.length))),
            length - rhs.length};
  }

  static u64 base_pow(size_t exp) {
    static std::vector<u64> pow{1};
    while (pow.size() <= exp) {
      pow.emplace_back(mult(pow.back(), base));
    }
    return pow[exp];
  }

 private:
  static u64 plus(u64 lhs, u64 rhs) {
    return (lhs += rhs) < mod ? lhs : lhs - mod;
  }

  static u64 minus(u64 lhs, u64 rhs) {
    return (lhs -= rhs) < mod ? lhs : lhs + mod;
  }

  static u64 mult(u128 lhs, u64 rhs) {
    lhs *= rhs;
    lhs = (lhs >> 61) + (lhs & mod);
    return lhs < mod ? lhs : lhs - mod;
  }
};

rolling_hashed::u64 rolling_hashed::base =
    random_number_generator<u64>(1 << 30, mod - 1)();

template <class str_type> struct rolling_hash_table {
  constexpr static size_t npos = -1;

  rolling_hash_table() = default;

  rolling_hash_table(str_type str) {
    std::reverse(std::begin(str), std::end(str));
    for (auto &&c : str)
      suffix.emplace_back(
          rolling_hashed{static_cast<rolling_hashed::u64>(c) + 1, 1} +
          suffix.back());
    std::reverse(suffix.begin(), suffix.end());
  }

  size_t size() const { return suffix.size() - 1; }

  rolling_hashed substr(size_t pos, size_t n = npos) const {
    assert(pos < size());
    return suffix[pos] - suffix[pos + std::min(n, size() - pos)];
  }

 private:
  std::vector<rolling_hashed> suffix{{}};
};
#line 6 "atcoder-workspace/abc141/e/e.cpp"

int main() {
  int n, len = 0;
  std::string s;
  std::cin >> n >> s;
  rolling_hash_table roll(s);
  while (len + 1 < n) {
    int mid = (len + n) / 2;
    std::unordered_map<uint_least64_t, int> id;
    bool ok = false;
    for (size_t i = 0; i < roll.size(); ++i) {
      auto val = roll.substr(i, mid).value;
      if (id.count(val))
        ok |= id[val] + mid <= i;
      else
        id[val] = i;
    }
    if (ok)
      len = mid;
    else
      n = mid;
  }
  std::cout << len << std::endl;
}


Measured memory_bytes: 3936