#include <iostream>
#include <set>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <climits>
#include <sstream>
#include <iomanip>
#include <map>
#include <stack>
#include <numeric>

using namespace std;

/*-----------------------------------------------------------------------------
　定義
 -----------------------------------------------------------------------------*/
#define ALL(x)					(x).begin(),(x).end()
#define REP(i, n)				for (int (i) = 0 ; (i) < (ll)(n) ; ++(i))
#define REPN(i, m, n)			for (int (i) = m ; (i) < (ll)(n) ; ++(i))
#define INF						(int)2e9
#define MOD						(1000 * 1000 * 1000 + 7)
#define Ceil(x, n)				(((((x))+((n)-1))/n))		/* Nの倍数に切り上げ割り算 */
#define CeilN(x, n)				(((((x))+((n)-1))/n)*n)		/* Nの倍数に切り上げ */
#define FloorN(x, n)			((x)-(x)%(n))				/* Nの倍数に切り下げ */
#define IsOdd(x)				(((x)&0x01UL) == 0x01UL)			
#define IsEven(x)				(!IsOdd((x)))						
#define M_PI					3.14159265358979323846
typedef long long				ll;
typedef unsigned long			ul;
typedef unsigned long long		ull;
typedef pair<int, int>			P;

/*-----------------------------------------------------------------------------
　処理
 -----------------------------------------------------------------------------*/
class SuffixArray {

public:
	int m_strLen;
	vector<int> sa;			// 順番 → インデックス
	vector<int> idxToOrder;	// インデックス → 順番

private:
	string srcStr;
	vector<int> rank;
	int m_i;

    bool lb_substr(const string &pat, int si = 0, int ti = 0) 
	{
		int sn = m_strLen;
		int tn = pat.size();
		while (si < sn && ti < tn) {
			if (srcStr[si] < pat[ti]) return true;
			if (srcStr[si] > pat[ti]) return false;
			si++, ti++;
		}
		return (si >= sn) && (ti < tn);
	}

public:
	SuffixArray(const string &s)
	{
		srcStr = s;
		m_strLen = s.size();

         /// @param i 元の文字列Sの位置i S[i:]
         /// @param j 元の文字列Sの位置j S[j:]
		auto compare_sa = [&](int a, int b)	{
			int rnkA = rank[a];
			int rnkB = rank[b];
			if (rnkA != rnkB) {
				return (rnkA < rnkB);
			} else {
				int aIdx = a + m_i;
				int bIdx = b + m_i;
				int ra = (aIdx <= m_strLen) ? rank[aIdx] : -1;
				int rb = (bIdx <= m_strLen) ? rank[bIdx] : -1;
				return ra < rb;
			}
		};

		// 最初は1文字
		sa.resize(m_strLen + 1);
		for (int i = 0; i <= m_strLen; i++) {
			sa[i] = i;
		}

		// ランクは文字コード
		rank.resize(m_strLen + 1);
		for (int i = 0; i < m_strLen; i++) {
			rank[i] = s[i];
		}
		rank[m_strLen] = -1;	// 空文字
	
		// i文字についてソートされてるところから2*i文字でソートする
		for (m_i = 1; m_i <= m_strLen; m_i *= 2) {
			sort(sa.begin(), sa.end(), compare_sa);
			
			auto nextRank = rank;
			nextRank[sa[0]] = 0;
			for (int j = 1; j <= m_strLen; j++) {
				nextRank[sa[j]] = nextRank[sa[j - 1]];
				if (compare_sa(sa[j - 1], sa[j])) {
					nextRank[sa[j]]++;
				}
			}
			rank = nextRank;
		}

		// 逆引き用
		idxToOrder.resize(m_strLen + 1);
		for (int i = 0; i <= m_strLen; i++) {
			idxToOrder[sa[i]] = i;
		}
	}

	// 文字列検索
	bool contain(const string &contStr)
	{
		int contStrLen = contStr.length();
		int lb = 0;
		int lu = m_strLen + 1;
		int mid = 0;
		while ((lb + 1) != lu) {
			mid = (lb + lu) / 2;
			if (srcStr.compare(sa[mid], contStrLen, contStr) < 0) {
				lb = mid;
			} else {
				lu = mid;
			}
		}
		return (srcStr.compare(sa[lu], contStrLen, contStr) == 0);
	}

	/// @param pat 文字列パターン
	/// @details 1 ~ n 正常(0は空文字)
	/// @details n + 1 .end()
	/// @details SA[high:]が下限
	int lower_bound(const string &pat) 
	{
		int low = 0;
		int high = m_strLen + 1;
		while (high - low > 1) {
			int mid = (low + high) / 2;
			if (lb_substr(pat, sa[mid])) low = mid;
			else high = mid;
		}
		return high;
	}
 
	/// @param pat 文字列パターン
	/// @details 1 ~ n 正常(0は空文字)
	/// @details n + 1 .end()
	/// @details SA[:high)が上限
	int upper_bound(string &pat) 
	{
		int low = 0;
		int high = m_strLen + 1;
		pat.back()++;
		while (high - low > 1) {
			int mid = (low + high) / 2;
			if (lb_substr(pat, sa[mid])) low = mid;
			else high = mid;
		}
		pat.back()--;
		return high;
	}

	void dumpSaStr()
	{
		int idx = 0;
		for (auto strIdx : sa) {
			cout<<  idx++ << " " << strIdx << " " << srcStr.substr(strIdx) << endl;
		}
	}
};

const int MAXN = 100010;
namespace SA {
    int rank[MAXN], tmp[MAXN];
    int n, k;
    bool compare_sa(int i, int j) {
        if (rank[i] != rank[j]) return rank[i] < rank[j];
        int ri = (i+k <= n) ? rank[i+k] : -1;
        int rj = (j+k <= n) ? rank[j+k] : -1;
        return ri < rj;
    }
    // suffix array を構築する
    // O(N log^2 N)
    // how to use: construct_saを呼ぶとsa配列にSuffixArrayを構築する
    void createSA(const string& s, int* sa) {
        n = s.size();
        // 最初は 1 文字ソート
        for (int i = 0; i <= n; i++) {
            sa[i] = i;
            rank[i] = i < n ? s[i] : -1;
        }
        for (k = 1; k <= n; k*=2) {
            sort(sa, sa+n+1, compare_sa);
            tmp[sa[0]] = 0;
            for (int i = 1; i <= n; i++) {
                tmp[sa[i]] = tmp[sa[i-1]] + (compare_sa(sa[i-1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= n; i++) rank[i] = tmp[i];
        }
    }
    namespace LCP {
        int rank[MAXN];
        // suffix array の情報をもとに longest common prefix を構築する
        // O(N)
        // hot to use: construct_lcpに文字列と suffix array の情報を入れると lcp 配列を作る
        void createLCP(const string& s, const int* sa, int* lcp) {
            int n = s.size();
            for (int i = 0; i <= n; i++) rank[sa[i]] = i;
            int h = 0;
            lcp[0] = 0;
            for (int i = 0; i < n; i++) {
                int j = sa[rank[i]-1];
                h = max(0, h-1);
                for (; j+h < n && i+h < n; h++) {
                    if (s[j+h] != s[i+h]) break;
                }
                lcp[rank[i]-1] = h;
            }
        }
        // sparse table を lcp 配列をもとに構築する
        // getLCP を呼ぶ前に読んでおかないとダメ
        // st[j][i] は lcp[i], lcp[i+1], ..., lcp[i+(2^j)-1] の最小値
        // lcp は (i, i+1) の共通接頭辞を求められるので, st[j][i] は (i, j) の共通接頭辞を求められる
        int st[21][MAXN];
        void initSparseTable(int n, const int* lcp) {
            int h = 1;
            while ((1<<h) < n) h++;
            for (int i = 0; i < n; i++) st[0][i] = lcp[i];
            for (int j = 1; j <= h; j++) {
                for (int i = 0; i <= n-(1<<j); i++) {
                    st[j][i] = min(st[j-1][i], st[j-1][i+(1<<(j-1))]);
                }
            }
        }
        inline int topBit(int t) {
            for (int i = 20; i >= 0; i--) {
                if ((1<<i)&t) return i;
            }
            return -1;
        }
        // suffix array の, "辞書順で" f 番目と s 番目の文字列における longest common prefix を求める
        // s.substr(f) と s.substr(s) の lcp じゃないからね
        int getLCP(int f, int s) {
            if (f > s) swap(f, s);
            int diff = topBit(s-f);
            return min(st[diff][f], st[diff][s-(1<<diff)]);
        }
    } // namespace LCP
} // namespace SA

bool compExec(SuffixArray &sa, int orderMax, int K, int subStrLen)
{
	if (subStrLen == 1) {
		for (int strPos = 0; strPos < sa.m_strLen; strPos++) {
			if (orderMax < sa.idxToOrder[strPos]) {
				return false;
			}
		}
		return true;
	} else {
		int strCnt = 0;
		for (int strPos = 0; strPos < sa.m_strLen; ) {
			strCnt++;
			if ((strPos + subStrLen) <= sa.m_strLen) {
				if (sa.idxToOrder[strPos] <= orderMax) {
					strPos += subStrLen;
				} else {
					strPos += (subStrLen - 1);
				}
			} else {
				break;
			}
		}
		return (strCnt <= K);
	}
}

#if 0
int main() 
{
	int K;
	string S;
	cin >> K >> S;
	if (K == 0) {
		cout << S << endl;	
		return 0;
	}
	if (K == 0) {
		cout << S << endl;	
		return 0;
	}

	int n = S.size();
 
	if (k == n) {
		char c = '1';
		REP(i, n) CHMAX(c, s[i]);
		OUT(c)BR;
		return 0;
	}
 
	const int L = (n + k - 1) / k;
 
	SuffixArray sa(s);
 
	V<int> inv(n + 1);
	REP(i, n + 1) inv[sa.sa[i]] = i;
 
	int ok = n, ng = 0;
	while (ok - ng > 1) {
		int i = ok + ng >> 1;
		int p = sa.sa[i];
 
		int now = 0;
		int cnt = 0;
		while (now < n) {
			++cnt;
			if (n - now < L) break;
			if (inv[now] <= i) {
				now += L;
			}
			else {
				now += L - 1;
			}
		}
		if (cnt <= k) ok = i;
		else ng = i;
	}
	OUT(s.substr(sa.sa[ok], L))BR;
 
	return 0;
}

#else 
int main()
{
	int K;
	string S;
	cin >> K >> S;
	K++;
	int n = S.size();
	if (K == 1) {
		cout << S << endl;	
		return 0;
	}
	if (K == n) {
		char c = '1';
		REP(i, n) c = max(c, S[i]);
		cout << c << endl;	
		return 0;
	}

	// 文字列長と探す個数
	int subStrLen = Ceil(n, K);
	
	// SA計算
	SuffixArray SA(S);
	// SA.dumpSaStr();

#if 0
	// 数字の候補
	vector<P> kouho;
	REP(i, (S.size() - subStrLen + 1)) {
		kouho.emplace_back(make_pair(SA.idxToOrder[i], i));
	}
	sort(ALL(kouho));

	// 候補を2分探索
	int lb = 0;
	int lu = kouho.size() + 1;
	int mid;
	while (lb + 1 != lu) {
		mid = (lb + lu) / 2;
		int midIdx = kouho[mid].second;
		int orderMax = SA.idxToOrder[midIdx];
		if (!compExec(SA, orderMax, K, subStrLen)) {
			lb = mid;
		} else {
			lu = mid;
		}
	}
#endif
	//*V<int> inv(n + 1);
	//REP(i, n + 1) inv[sa.sa[i]] = i;
 
	int ok = n, ng = 0;
	while (ok - ng > 1) {
		int i = (ok + ng) / 2;
		int p = SA.sa[i];
 
		int now = 0;
		int cnt = 0;
		while (now < n) {
			++cnt;
			if (n - now < subStrLen) break;
			if (SA.idxToOrder[now] <= i) {
				now += subStrLen;
			}
			else {
				now += subStrLen - 1;
			}
		}
		if (cnt <= K) ok = i;
		else ng = i;
	}

	cout << S.substr(SA.sa[ok], subStrLen) << endl;	
	return 0;
}

#endif

Measured memory_bytes: 1664