Problem:
Score : 1000 points

Problem Statement

You are given a string S consisting of digits between 1 and 9, inclusive.
You will insert at most K commas (,) into this string to separate it into multiple numbers.

Your task is to minimize the maximum number among those produced by inserting commas. Find minimum possible such value.

Constraints

0 ≦ K < |S| ≦ 100,000

S consists of digits between 1 and 9, inclusive.

Partial Scores

In the test set worth 100 points, |S| ≦ 2.

In the test set worth another 100 points, |S| ≦ 16.

In the test set worth another 200 points, |S| ≦ 100.

In the test set worth another 200 points, |S| ≦ 2,000.

Input

The input is given from Standard Input in the following format:

K
S

Output

Print the minimum possible value.

Sample Input 1

2
15267315

Sample Output 1

315

When the string is separated into 152, 67 and 315, the maximum among these is 315, which is the minimum possible value.

Sample Input 2

0
12456174517653111

Sample Output 2

12456174517653111

12456174517653111 itself is the answer.

Sample Input 3

8
127356176351764127645176543176531763517635176531278461856198765816581726586715987216581

Sample Output 3

5317635176

Solution in C++ (GCC 9.2.1) (judge verdict: Wrong Answer)

///#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
///#pragma GCC target("sse,sse2,sse3,ssse3,sse4,abm,mmx,popcnt,avx,avx2,tune=native")

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>

/*
    zet:
        find_by_order(k): k-stat [k > 0]
        order_of_key(k) : {el < k}

    gp_hash_table<key, val, custom_hash>

    rope<T>:
        iterators: mutable_begin, ..
        methods  : erase, insert, substr, ..
*/

#define all(x) (x).begin(), (x).end()
#define sz(x) (int)((x).size())
#define em_back emplace_back

using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;

using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

template<typename T>
using zet = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

mt19937 eng(chrono::steady_clock::now().time_since_epoch().count());

const int maxlen = 1e5 + 4;
const int SQ = sqrt(1e5 + 4) + 4;
const int alphabet = 10;
const int LG = 18;

int k;
string cs;

int n;
char s[maxlen];

void read() {
    cin >> k >> cs;
    n = sz(cs);
    for (int i = 0; i < n; ++i) {
        s[i] = cs[i] - '0';
    }
}

int p[maxlen], cnt[maxlen], c[LG][maxlen];
int pn[maxlen], cn[maxlen];
int logtab[maxlen];

void prepare() {
    memset (cnt, 0, alphabet * sizeof(int));
    for (int i=0; i<n; ++i)
        ++cnt[s[i]];
    for (int i=1; i<alphabet; ++i)
        cnt[i] += cnt[i-1];
    for (int i=0; i<n; ++i)
        p[--cnt[s[i]]] = i;
    c[0][p[0]] = 0;
    int classes = 1;
    for (int i=1; i<n; ++i) {
        if (s[p[i]] != s[p[i-1]])  ++classes;
        c[0][p[i]] = classes-1;
    }

    for (int h=0; (1<<h)<n; ++h) {
        for (int i=0; i<n; ++i) {
            pn[i] = p[i] - (1<<h);
            if (pn[i] < 0)  pn[i] += n;
        }
        memset (cnt, 0, classes * sizeof(int));
        for (int i=0; i<n; ++i)
            ++cnt[c[h][pn[i]]];
        for (int i=1; i<classes; ++i)
            cnt[i] += cnt[i-1];
        for (int i=n-1; i>=0; --i)
            p[--cnt[c[h][pn[i]]]] = pn[i];
        cn[p[0]] = 0;
        classes = 1;
        for (int i=1; i<n; ++i) {
            int mid1 = (p[i] + (1<<h)) % n,  mid2 = (p[i-1] + (1<<h)) % n;
            if (c[h][p[i]] != c[h][p[i-1]] || c[mid1] != c[mid2])
                ++classes;
            cn[p[i]] = classes-1;
        }
        memcpy (c[h + 1], cn, n * sizeof(int));
    }

    logtab[1] = 0;
    for (int i = 2; i < maxlen; ++i) {
        logtab[i] = 1 + logtab[i >> 1];
    }
}

inline int compare(int i, int j, int l) {
    if (i == -1) {
        return -1;
    }
    int pw = logtab[l];
	pii a = make_pair (c[pw][i], c[pw][i+l-(1<<pw)]);
	pii b = make_pair (c[pw][j], c[pw][j+l-(1<<pw)]);
	return a == b ? 0 : a < b ? -1 : 1;
}

int dp[maxlen][SQ];

string calc1() { /// k < sqrt(n)
    int slow = n / (k + 1);
    int speed = slow + !!(n % (k + 1));

    int cnt = n % (k + 1);

    if (cnt == 0) {
        string res = cs.substr(0, slow);
        for (int i = slow; i < n; i += slow) {
            res = max(res, cs.substr(i, slow));
        }
        return res;
    }

    dp[n][0] = -2;
    for (int i = n - slow; i >= 0; --i) {
        for (int j = cnt; j >= 0; --j) {
            int& res = dp[i][j];

            if (j == 1 && i + speed <= n) {
                int& speedTo = dp[i + speed][0];
                if (speedTo == -2) {
                    res = i;
                }
            }

            if (j > 1 && i + speed <= n) {
                int& speedTo = dp[i + speed][j - 1];
                if (speedTo != -1) {
                    int cmp = compare(i, speedTo, speed);
                    if (cmp <= 0) {
                        res = speedTo;
                    } else {
                        res = i;
                    }
                }
            }

            int& slowTo = dp[i + slow][j];
            if (slowTo != -1) {
                if (j == 0) {
                    res = -2;
                } else {
                    if (res == -1) {
                        res = slowTo;
                    } else {
                        int cmp = compare(res, slowTo, speed);
                        if (cmp == 1) {
                            res = slowTo;
                        }
                    }
                }
            }
        }
    }

    int pos = dp[0][cnt];
    return cs.substr(pos, speed);
}

typedef vector<int> lnum;
const int base = 10;

void add(lnum&a, lnum& b) {
    int carry = 0;
    for (size_t i=0; i<max(a.size(),b.size()) || carry; ++i) {
        if (i == a.size())
            a.push_back (0);
        a[i] += carry + (i < b.size() ? b[i] : 0);
        carry = a[i] >= base;
        if (carry)  a[i] -= base;
    }
}

void del2(lnum& a) {
    int carry = 0;
    for (int i=(int)a.size()-1; i>=0; --i) {
        long long cur = a[i] + carry * 1ll * base;
        a[i] = int (cur >> 1);
        carry = int (cur & 1);
    }
    while (a.size() > 1 && a.back() == 0)
        a.pop_back();
}

bool eq(lnum& a, lnum& b) {
    if (sz(a) != sz(b)) {
        return false;
    }
    for (int i = 0; i < sz(b); ++i) {
        if (a[i] != b[i]) {
            return false;
        }
    }
    return true;
}

bool check(lnum& m) {
    int cnt = 0;
    if (sz(m) == 1 && n - 1 > k) {
        return false;
    }
    for (int i = 0; i < n;) {
        if (sz(m) == 1) {
            if (s[i] > m[0]) {
                return false;
            }
            ++i;
        } else if (sz(m) > 1) {
            if (i + sz(m) - 1 >= n) {
                break;
            }
            bool tmp = true;
            for (int j = 0; j < sz(m); ++j) {
                if (s[i + j] > m[sz(m) - 1 - j]) {
                    tmp = false;
                    break;
                }
            }
            i += sz(m) - 1 + tmp;
            if (i == n) {
                break;
            }
            ++cnt;
        }

    }
    return cnt <= k;
}

string calc2() {
    lnum l = {0};
    lnum r;
    for (int i = 0; i <= n / (k + 1) + 1; ++i) {
        r.em_back(9);
    }

    while (true) {
        lnum m = l;
        add(m, r);
        del2(m);

        if (eq(m, l) || eq(m, r)) {
            break;
        }

        if (check(m)) {
            r = m;
        } else {
            l = m;
        }
    }

    string res = "";
    for (int d : r) {
        res.push_back('0' + d);
    }
    reverse(all(res));
    return res;
}

void solve() {
    read();
    prepare();

    memset(dp, -1, sizeof dp);
    int board = sqrt(n);
    string res;
    if (k > board) {
        res = calc2();
    } else {
        res = calc1();
    }
    cout << res << "\n";
}

int main() {
    ios::sync_with_stdio(0);
    cout.tie(0), cin.tie(0);

    int z = 1;
    /// cin >> z;

    while (z--) {
        solve();
    }

    return 0;
}