Problem:
Problem H: Hth Number
Problem
長さ$N$の文字列$S$がある。$S$に含まれる文字はすべて0以上9以下の数字である。
$S$のすべての部分文字列から作られる数を全列挙してできた項数$\frac{N\times(N+1)}{2}$の数列を作った時、
その数列の中で$H$番目に小さい値を求めよ。
Input
入力は以下の形式で与えられる。
$N$ $H$
$S$
入力はすべて整数で与えられる。
1行目に$N$と$H$が空白区切りで与えられる。
2行目に長さ$N$の文字列$S$が与えられる。
Constraints
入力は以下の条件を満たす。
$1 \leq N \leq 10^5$
$1 \leq H \leq \frac{N \times (N+1)}{2}$
$|S| = N$
$S$に含まれる文字はすべて0, 1, 2, 3, 4, 5, 6, 7, 8, 9のいずれかである
Output
$H$番目の値を1行に出力せよ。
(出力の先頭に余計な0は含んではならない。)
Sample Input 1
2 3
00
Sample Output 1
0
Sample Input 2
4 9
0012
Sample Output 2
12
Sample Input 3
5 13
10031
Sample Output 3
100
Sample Input3の場合、10031の部分文字列から作られる数は以下の通りである。
1, 0, 0, 3, 1
10, 00, 03, 31
100, 003, 031
1003, 0031
10031
これらをを小さい順に並べると
0, 0, 0, 1, 1, 3, 3, 3, 10, 31, 31, 31, 100, 1003, 10031 になり、13番目に小さい値は100である。

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

#define NUM1 1000000009
#define NUM2 99999883

struct Info{
	ull hash_1,hash_2;
};
ull HASH[SIZE][2],POW[SIZE][2];

ll T_length,H,digit;
ll table[SIZE],ruisekiwa[SIZE];
vector<int> V;
char T[SIZE];

bool IS_SAME(Info left,Info right){
	if(left.hash_1 == right.hash_1 && left.hash_2 == right.hash_2)return true;
	else{
		return false;
	}
}

Info calcHash(int left,int right){

	Info ret;

	int length = right-left+1;

	//indexのずれに注意:T[right]までのハッシュ値はHASH[right+1]に記録されている
	ret.hash_1 = HASH[right+1][0]-HASH[left][0]*POW[length][0];
	ret.hash_2 = HASH[right+1][1]-HASH[left][1]*POW[length][1];

	return ret;
}

//AとBの一致長さを返す
ll calc_match_len(int start_A,int start_B,int length){

	ll left = 0,right = length-1,mid = (left+right)/2;
	ll match_len = 0;
	Info tmp_A,tmp_B;

	while(left <= right){

		tmp_A = calcHash(start_A,start_A+mid);
		tmp_B = calcHash(start_B,start_B+mid);

		if(IS_SAME(tmp_A,tmp_B)){
			match_len = mid+1;
			left = mid+1;
		}else{
			right = mid-1;
		}
		mid = (left+right)/2;
	}

	return match_len;
}

bool compare(int a,int b){

	ll match_len = calc_match_len(a,b,digit);

	return T[a+match_len] < T[b+match_len];
}


int main(){

	scanf("%lld %lld",&T_length,&H);

	scanf("%s",T);

	ll num_zero = 0;
	for(int i = 0; i < T_length; ){
		if(T[i] != '0'){

			i += 1;
			continue;
		}
		ll count = 0;
		for(;i+count < T_length && T[i+count] == '0'; count++);

		num_zero += (count*(count+1))/2;
		i += count;
	}

	if(num_zero >= H){

		printf("0\n");
		return 0;
	}

	//2通りのハッシュ値を計算する
	HASH[0][0] = 0;
	HASH[0][1] = 0;
	POW[0][0] = 1;
	POW[0][1] = 1;

	//Tのハッシュ値を求める
	for(int i = 1; i <= T_length; i++){
		HASH[i][0] = T[i-1] + HASH[i-1][0]*NUM1;
		HASH[i][1] = T[i-1] + HASH[i-1][1]*NUM2;

		POW[i][0] = POW[i-1][0]*NUM1;
		POW[i][1] = POW[i-1][1]*NUM2;
	}

	for(int i = 0; i <= T_length; i++){

		ruisekiwa[i] = 0; //桁iの数がいくつあるか
	}

	table[T_length] = T_length;
	for(int i = T_length-1; i >= 0; i--){

		if(T[i] != '0'){

			table[i] = i;
		}else{

			table[i] = table[i+1];
		}

		ruisekiwa[T_length-table[i]]++;
		ruisekiwa[0]--;
	}

	for(int i = T_length-1; i >= 0; i--){

		ruisekiwa[i] += ruisekiwa[i+1];
	}

	digit = 0;
	ll sum = num_zero;

	for(int i = 1; i <= T_length; i++){

		if(sum+ruisekiwa[i] >= H){
			digit = i;
			break;
		}
		sum += ruisekiwa[i];
	}

	//printf("sum:%lld digit:%lld\n",sum,digit);

	for(int i = 0; i <= T_length; i++){

		if(table[i]+digit > T_length)break;

		V.push_back(table[i]);
	}

	sort(V.begin(),V.end(),compare);

	for(int i = 0; i < digit; i++){

		printf("%c",T[V[H-(sum+1)]+i]);
	}
	printf("\n");

	return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 8004
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

#define NUM1 1000000009
#define NUM2 99999883

struct Info{
	ull hash_1,hash_2;
};
ull HASH[SIZE][2],POW[SIZE][2];

ll T_length,H,range,max_range,last_range;
ll Rank[SIZE]; //接尾辞文字列の開始位置iの、辞書順にsortした際の順位表
ll Suffix_Array[SIZE]; //接尾辞文字列の開始位置<インデックス>→毎回、辞書順に開始位置をソートする
ll Work[SIZE]; //作業用配列
ll table[SIZE],ruisekiwa[SIZE];

char T[SIZE];

bool IS_SAME(Info left,Info right){
	if(left.hash_1 == right.hash_1 && left.hash_2 == right.hash_2)return true;
	else{
		return false;
	}
}

Info calcHash(int left,int right){

	Info ret;

	int length = right-left+1;

	//indexのずれに注意:T[right]までのハッシュ値はHASH[right+1]に記録されている
	ret.hash_1 = HASH[right+1][0]-HASH[left][0]*POW[length][0];
	ret.hash_2 = HASH[right+1][1]-HASH[left][1]*POW[length][1];

	return ret;
}

//AとBの一致長さを返す
ll calc_match_len(int start_A,int start_B,int length){

	ll left = 0,right = length-1,mid = (left+right)/2;
	ll match_len = 0;
	Info tmp_A,tmp_B;

	while(left <= right){

		tmp_A = calcHash(start_A,start_A+mid);
		tmp_B = calcHash(start_B,start_B+mid);

		if(IS_SAME(tmp_A,tmp_B)){
			match_len = mid+1;
			left = mid+1;
		}else{
			right = mid-1;
		}
		mid = (left+right)/2;
	}

	return match_len;
}


//まずrank[a]とrank[b]を比較、等しければrank[a+range],rank[b+range]を比較
bool compare_Suffix_Array(int a,int b){
	if(Rank[a] != Rank[b])return Rank[a] < Rank[b];
	else{
		int rank_a = a + range <= T_length ? Rank[a + range]:-1; //rangeを足した部分が範囲外なら、最高にするため、rankを-1にする
		int rank_b = b + range <= T_length ? Rank[b + range]:-1;
		return rank_a < rank_b;
	}
}

bool final_compare_Suffix_Array(int a,int b){
	if(Rank[a] != Rank[b])return Rank[a] < Rank[b];
	else{

		ll len_A = T_length-Suffix_Array[a],len_B =T_length-Suffix_Array[b];

		ll match_len = calc_match_len(Suffix_Array[a],Suffix_Array[b],min(len_A,len_B));

		return T[Suffix_Array[a]+match_len] < T[Suffix_Array[b]+match_len];
	}
}

//文字列Tの接尾辞配列を構築
void make_Suffix_Array(){
	for(int i = 0; i <= T_length; i++){
		Suffix_Array[i] = table[i];
		Rank[table[i]] = i < T_length? (T[table[i]]-'0'):-1; //初期ランク設定:T[T_length]は空文字なので、最高となるように-1とする
	}

	//range,2*range,4*range,とソート幅を次第に伸ばしていく
	for(range = 1; range <= T_length; range*=2){

		if(2*range > max_range)break;

		sort(Suffix_Array,Suffix_Array+(T_length+1),compare_Suffix_Array); //range文字の幅でsuffix_Arrayをソート

		Work[Suffix_Array[0]] = 0;
		for(int i = 1; i <= T_length; i++){
			Work[Suffix_Array[i]] = Work[Suffix_Array[i-1]] + (compare_Suffix_Array(Suffix_Array[i-1],Suffix_Array[i])?1:0);
		}
		for(int i = 0; i <= T_length; i++){
			Rank[i] = Work[i];
		}

		last_range = range;
	}

	sort(Suffix_Array,Suffix_Array+(T_length+1),final_compare_Suffix_Array);
}


int main(){

	scanf("%lld %lld",&T_length,&H);

	scanf("%s",T);

	ll num_zero = 0;
	for(int i = 0; i < T_length; ){
		if(T[i] != '0'){

			i += 1;
			continue;
		}
		ll count = 0;
		for(;i+count < T_length && T[i+count] == '0'; count++);

		num_zero += (count*(count+1))/2;
		i += count;
	}

	if(num_zero >= H){

		printf("0\n");
		return 0;
	}

	//2通りのハッシュ値を計算する
	HASH[0][0] = 0;
	HASH[0][1] = 0;
	POW[0][0] = 1;
	POW[0][1] = 1;

	//Tのハッシュ値を求める
	for(int i = 1; i <= T_length; i++){
		HASH[i][0] = T[i-1] + HASH[i-1][0]*NUM1;
		HASH[i][1] = T[i-1] + HASH[i-1][1]*NUM2;

		POW[i][0] = POW[i-1][0]*NUM1;
		POW[i][1] = POW[i-1][1]*NUM2;
	}

	for(int i = 0; i <= T_length; i++){

		ruisekiwa[i] = 0; //桁iの数がいくつあるか
	}

	table[T_length] = T_length;
	for(int i = T_length-1; i >= 0; i--){

		if(T[i] != '0'){

			table[i] = i;
		}else{

			table[i] = table[i+1];
		}

		ruisekiwa[T_length-table[i]]++;
		ruisekiwa[0]--;
	}

	for(int i = T_length-1; i >= 0; i--){

		ruisekiwa[i] += ruisekiwa[i+1];
	}

	ll digit = 0;
	ll sum = num_zero;

	for(int i = 1; i <= T_length; i++){

		if(sum+ruisekiwa[i] >= H){
			digit = i;
			break;
		}
		sum += ruisekiwa[i];
	}

	max_range = digit;
	make_Suffix_Array();

	for(int i = 0; i <= T_length; i++){

		ll head = Suffix_Array[i];

		if(T_length-head < digit)continue;

		sum++;
		if(sum == H){

			for(int k = 0; k < digit; k++){

				printf("%c",T[head+k]);
			}
			printf("\n");
			return 0;
		}
	}

	return 0;
}
accuracy: 0.6949152542372882
time_ms: 70
memory_kb: 9816
final_rank: 19

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 100005

#define NUM1 1000000007
#define NUM2 99999883

struct Info{
	ull hash_1,hash_2;
};
ull HASH[SIZE][2],POW[SIZE][2];

ll T_length,H,range,max_range,last_range;
ll Rank[SIZE]; //接尾辞文字列の開始位置iの、辞書順にsortした際の順位表
ll Suffix_Array[SIZE]; //接尾辞文字列の開始位置<インデックス>→毎回、辞書順に開始位置をソートする
ll Work[SIZE]; //作業用配列
ll table[SIZE],ruisekiwa[SIZE];

char T[SIZE];

bool IS_SAME(Info left,Info right){
	if(left.hash_1 == right.hash_1 && left.hash_2 == right.hash_2)return true;
	else{
		return false;
	}
}

Info calcHash(int left,int right){

	Info ret;

	int length = right-left+1;

	//indexのずれに注意:T[right]までのハッシュ値はHASH[right+1]に記録されている
	ret.hash_1 = HASH[right+1][0]-HASH[left][0]*POW[length][0];
	ret.hash_2 = HASH[right+1][1]-HASH[left][1]*POW[length][1];

	return ret;
}

//AとBの一致長さを返す
ll calc_match_len(int start_A,int start_B,int length){

	ll left = 0,right = length-1,mid = (left+right)/2;
	ll match_len = 0;
	Info tmp_A,tmp_B;

	while(left <= right){

		tmp_A = calcHash(start_A,start_A+mid);
		tmp_B = calcHash(start_B,start_B+mid);

		if(IS_SAME(tmp_A,tmp_B)){
			match_len = mid+1;
			left = mid+1;
		}else{
			right = mid-1;
		}
		mid = (left+right)/2;
	}

	return match_len;
}


//まずrank[a]とrank[b]を比較、等しければrank[a+range],rank[b+range]を比較
bool compare_Suffix_Array(int a,int b){
	if(Rank[a] != Rank[b])return Rank[a] < Rank[b];
	else{
		int rank_a = a + range <= T_length ? Rank[a + range]:-1; //rangeを足した部分が範囲外なら、最高にするため、rankを-1にする
		int rank_b = b + range <= T_length ? Rank[b + range]:-1;
		return rank_a < rank_b;
	}
}

bool final_compare_Suffix_Array(int a,int b){
	if(Rank[a] != Rank[b])return Rank[a] < Rank[b];
	else{

		ll len_A = T_length-Suffix_Array[a],len_B =T_length-Suffix_Array[b];

		ll match_len = calc_match_len(Suffix_Array[a],Suffix_Array[b],min(len_A,len_B));

		return T[Suffix_Array[a]+match_len] < T[Suffix_Array[b]+match_len];
	}
}

//文字列Tの接尾辞配列を構築
void make_Suffix_Array(){
	for(int i = 0; i <= T_length; i++){
		Suffix_Array[i] = table[i];
		Rank[table[i]] = i < T_length? (T[table[i]]-'0'):-1; //初期ランク設定:T[T_length]は空文字なので、最高となるように-1とする
	}

	//range,2*range,4*range,とソート幅を次第に伸ばしていく
	for(range = 1; range <= T_length; range*=2){

		if(2*range > max_range)break;

		sort(Suffix_Array,Suffix_Array+(T_length+1),compare_Suffix_Array); //range文字の幅でsuffix_Arrayをソート

		Work[Suffix_Array[0]] = 0;
		for(int i = 1; i <= T_length; i++){
			Work[Suffix_Array[i]] = Work[Suffix_Array[i-1]] + (compare_Suffix_Array(Suffix_Array[i-1],Suffix_Array[i])?1:0);
		}
		for(int i = 0; i <= T_length; i++){
			Rank[i] = Work[i];
		}

		last_range = range;
	}

	sort(Suffix_Array,Suffix_Array+(T_length+1),final_compare_Suffix_Array);
}


int main(){

	scanf("%lld %lld",&T_length,&H);

	scanf("%s",T);

	ll num_zero = 0;
	for(int i = 0; i < T_length; ){
		if(T[i] != '0'){

			i += 1;
			continue;
		}
		ll count = 0;
		for(;i+count < T_length && T[i+count] == '0'; count++);

		num_zero += (count*(count+1))/2;
		i += count;
	}

	if(num_zero >= H){

		printf("0\n");
		return 0;
	}

	//2通りのハッシュ値を計算する
	HASH[0][0] = 0;
	HASH[0][1] = 0;
	POW[0][0] = 1;
	POW[0][1] = 1;

	//Tのハッシュ値を求める
	for(int i = 1; i <= T_length; i++){
		HASH[i][0] = T[i-1] + HASH[i-1][0]*NUM1;
		HASH[i][1] = T[i-1] + HASH[i-1][1]*NUM2;

		POW[i][0] = POW[i-1][0]*NUM1;
		POW[i][1] = POW[i-1][1]*NUM2;
	}

	for(int i = 0; i <= T_length; i++){

		ruisekiwa[i] = 0; //桁iの数がいくつあるか
	}

	table[T_length] = T_length;
	for(int i = T_length-1; i >= 0; i--){

		if(T[i] != '0'){

			table[i] = i;
		}else{

			table[i] = table[i+1];
		}

		ruisekiwa[T_length-table[i]]++;
		ruisekiwa[0]--;
	}

	for(int i = T_length-1; i >= 0; i--){

		ruisekiwa[i] += ruisekiwa[i+1];
	}

	ll digit = 0;
	ll sum = num_zero;

	for(int i = 1; i <= T_length; i++){

		if(sum+ruisekiwa[i] >= H){
			digit = i;
			break;
		}
		sum += ruisekiwa[i];
	}

	max_range = digit;
	make_Suffix_Array();

	for(int i = 0; i <= T_length; i++){

		ll head = Suffix_Array[i];

		if(T_length-head < digit)continue;

		sum++;
		if(sum == H){

			for(int k = 0; k < digit; k++){

				printf("%c",T[head+k]);
			}
			printf("\n");
			return 0;
		}
	}

	return 0;
}
accuracy: 0.6949152542372882
time_ms: 70
memory_kb: 9772
final_rank: 18

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>

void set_rank(std::vector<int>& rank, const std::vector<int>& sorted_indices, const std::vector<long long int>& compare_value) {
	rank[sorted_indices.front()] = 0;
	for (auto i = 1; i < sorted_indices.size(); ++i) {
		rank[sorted_indices[i]] = rank[sorted_indices[i - 1]] + (compare_value[sorted_indices[i]] == compare_value[sorted_indices[i - 1]] ? 0 : 1);
	}
}
std::vector<int> make_suffix_array(const std::string& str) {
	std::vector<int> rank(str.size()), indices(str.size());
	std::vector<long long int> compare_value(str.size());
	std::iota(indices.begin(), indices.end(), 0);
	std::copy(str.begin(), str.end(), compare_value.begin());
	const auto comparator = [&compare_value](int i, int j) {return compare_value[i] < compare_value[j]; };
	std::sort(indices.begin(), indices.end(), comparator);
	set_rank(rank, indices, compare_value);
	for (auto i = 0; (1 << i) < str.size(); ++i) {
		for (auto j = 0; j < str.size(); ++j) {
			compare_value[j] = rank[j] * (str.size() + 1LL) + (j + (1 << i) < str.size() ? rank[j + (1 << i)] : -1);
		}
		std::sort(indices.begin(), indices.end(), comparator);
		set_rank(rank, indices, compare_value);
	}
	return indices;
}
template<typename Idx, typename F>
int upper_bound(Idx from, Idx until, const F& predicate) {
	while (from < until) {
		const auto mid = (from + until) / 2;
		if (predicate(mid)) until = mid;
		else from = mid + 1;
	}
	return until;
}


int main() {
	int n; long long int h; std::cin >> n >> h;
	std::string str; std::cin >> str;
	std::vector<int> next_positive(n, 0);
	for (auto i = 0; i < str.size(); ++i) if (str[i] == '0') next_positive[i] = 1;
	for (auto i = 2; i <= str.size(); ++i) if (str[str.size() - i] == '0')  next_positive[str.size() - i] += next_positive[str.size() - i + 1];
	std::vector<long long int> substrings(n + 1, 0);
	long long int for_zero = 0;
	for (auto i = 0; i < next_positive.size(); ++i) {
		const auto head = next_positive[i] + i;
		if (head != n) substrings[n - head]++;
		if (i == 0 || str[i - 1] != '0') {
			for_zero += next_positive[i] * (next_positive[i] + 1LL) >> 1;
		}
	}
	for (int i = substrings.size() - 2; i > 0; --i) substrings[i] += substrings[i + 1];
	for (auto i = 1; i < substrings.size(); ++i) substrings[i] += substrings[i - 1];
	const auto length = std::distance(substrings.begin(), std::lower_bound(substrings.begin(), substrings.end(), h - for_zero));
	if (length == 0) {
		std::cout << "0\n";
	}else {
		const auto sa = make_suffix_array(str);
		const auto rank = h - substrings[length - 1] - for_zero;
		std::vector<int> substr, multipler(n, 0);
		for (const auto i : sa) {
			if (str[i] == '0') {
				const auto head = i + next_positive[i];
				if (head != n) multipler[head]++;
			}else if (0 <= i && i <= n - length) {
				while (multipler[i]-- >= 0) substr.push_back(i);
			}
		}
		std::cout << str.substr(substr[rank - 1], length) << std::endl;
	}
}
accuracy: 1
time_ms: 40
memory_kb: 5860
final_rank: 2

code_snippet: #include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<iomanip>
#include<math.h>
#include<complex>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<functional>
#include<assert.h>
#include<numeric>
using namespace std;
#define REP(i,m,n) for(int i=(int)(m) ; i < (int) (n) ; ++i )
#define rep(i,n) REP(i,0,n)
typedef long long ll;
typedef pair<int,int> pint;
typedef pair<ll,int> pli;
const int inf=1e9+7;
const ll longinf=1LL<<60 ;
const ll mod=1e9+7 ;



ll n,k,h,ran[101010],tmp[101010],sa[101010];

bool compare_sa(int i,int j){
    if(ran[i]!=ran[j])return ran[i]<ran[j];
    int ri = (i+k<=n?ran[i+k] : -1);
    int rj = (j+k<=n?ran[j+k] : -1);
    return ri<rj;
}

void constract_sa(string&s){
    rep(i,n+1){
        sa[i]=i;
        ran[i]=(i<n?s[i] : -1);
    }
    for(k=1 ; k<=n ;k*=2 ){
        sort(sa,sa+n+1,compare_sa);
        tmp[sa[0]]=0;
        rep(i,n){
            tmp[sa[i+1]]=tmp[sa[i]]+compare_sa(sa[i],sa[i+1]);
        }
        rep(i,n+1)ran[i]=tmp[i];
    }
}
int main(){
    cin>>n>>h;
    string s;
    cin>>s;
    bool all_zero=true;
    rep(i,n)if(s[i]!='0')all_zero=false;
    if(all_zero){
        cout<<0<<endl;
        return 0;
    }
    vector<int> nonzero(n,-1);
    nonzero[0]=-1;
    reverse(s.begin(),s.end());
    rep(i,n){
        if(s[i]!='0')nonzero[i]=i;
        else if(i!=0) nonzero[i]=nonzero[i-1];
    }
    reverse(s.begin(),s.end());
    vector<ll> cnt(n+1);
    rep(i,n){
        cnt[nonzero[i]+1]++;
    }
    rep(i,n-1)cnt[n-i-1]+=cnt[n-i];
    rep(i,n)if(nonzero[i]!=-1)cnt[0]+=i-nonzero[i];
    int keta=0;
    while(h-cnt[keta]>0){
        h-=cnt[keta];
        ++keta;
    }
    if(!keta){
        cout<<0<<endl;
        return 0;
    }
    constract_sa(s);
    rep(i,n+1)sa[ran[i]]=i;
    vector<int> cnt2(n+1);
    rep(i,n)cnt2[n-nonzero[i]-1]++;
    int ans=-1;
    rep(i,n+1){
        if(n-sa[i]<keta)continue;
        if(h<=cnt2[sa[i]]){
            ans=sa[i];
            break;
        }
        h-=cnt2[sa[i]];
    }
    cout<<s.substr(ans,keta)<<endl;
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 6776
final_rank: 11

code_snippet: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdlib>
#define int long long
#define rep(i, n) for(i = 0; i < n; i++)
using namespace std;

int n, h;
string s;
int cnts[100001];		//cnts[i] = i桁(no leading 0)の数がいくつあるか. "0"や"00"は0桁としてカウント.
int begin_cnts[100001];

//spagetti-source, 動く形に書き直すのが難しかった()
struct SAComp {
  const int h, *g;
  SAComp(int h, int* g) : h(h), g(g) {}
  bool operator() (int a, int b) {
    return a == b ? false : g[a] != g[b] ? g[a] < g[b] : g[a+h] < g[b+h];
  }
};
vector<int> construct_sa(string s) {
  int n = s.length();
  int *g = new int[n+1];
  int *b = new int[n+1];
  int *v = new int[n+1];
  int i;
  rep(i,n+1) v[i] = i, g[i] = s[i];
  b[0] = 0; b[n] = 0;

  sort(v, v+n+1, SAComp(0, g));
  for(int h = 1; b[n] != n ; h *= 2) {
    SAComp comp(h, g);
    sort(v, v+n+1, comp);
    rep(i, n) b[i+1] = b[i] + comp(v[i], v[i+1]);
    rep(i, n+1) g[v[i]] = b[i];
  }
  delete[] g;
  delete[] b;
  
  vector<int> ret;
  rep(i, n + 1) ret.push_back(v[i]);
  delete[] v;
  return ret;
}

/*vector<int> construct_sa(string &s) {
	vector<string> vs;
	int i, j;
	
	rep(i, s.length() + 1) {
		string suf;
		for (j = i; j < s.length(); j++) suf += s[j];
		vs.push_back(suf);
	}
	sort(vs.begin(), vs.end());
	
	vector<int> sa;
	rep(i, vs.size()) sa.push_back(s.length() - vs[i].length());
	return sa;
}*/

signed main() {
	int i, j;
	
	cin >> n >> h >> s;
	
	j = 0;
	rep(i, n) {
		if (j < i) j = i;
		for (; j < n; j++) if (s[j] != '0') break;
		
		cnts[0] += j - i;
		cnts[1] -= j - i;
		cnts[1] += 1;
		cnts[n - j + 1] -= 1;
	}
	rep(i, n) cnts[i + 1] += cnts[i];
	
	int cnt = 0;
	rep(i, n + 1) {
		cnt += cnts[i];
		if (cnt >= h) break;
	}
	
	int keta = i;
	if (keta == 0) { cout << 0 << endl; return 0; }
	
	cnt = 0;
	rep(i, keta) { cnt += cnts[i]; }
	h = h - cnt;
	
	j = n - keta;
	for (i = n - keta; i >= 0; i--) {
		if (s[i] == '0') continue;
		if (j >= i) j = i - 1;
		for (; j >= 0; j--) if (s[j] != '0') break;
		begin_cnts[i] = i - j;
	}
	
	vector<int> sa = construct_sa(s);
	
	//rep(i, sa.size()) cout << "sa[" << i << "] = " << sa[i] << endl;
	
	rep(i, sa.size()) {
		if (sa[i] == s.length()) continue;	//空文字列
		if (s[sa[i]] == '0') continue;		//先頭が0のものは無視
		h -= begin_cnts[sa[i]];				//[0…0], s[sa[i]], …であって、桁数= ketaになるパターン数
		if (h <= 0) break;
	}
	
	int offset = sa[i];
	string ans;
	rep(i, keta) ans += s[offset + i];
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 6836
final_rank: 4

code_snippet: #include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <bitset>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef long long int ll;
typedef pair<int, int> P;
int n, k;
int rk[100002];
int tmp[100002];

bool compare_sa(int i, int j){
  if(rk[i]!=rk[j]) return rk[i]<rk[j];
  else{
    int ri, rj;
    if(i+k<=n) ri=rk[i+k];
    else ri=-1;
    if(j+k<=n) rj=rk[j+k];
    else rj=-1;
    return ri<rj;
  }
}

void construct_sa(string s, int *sa){
  n=s.size();
  for(int i=0; i<=n; i++){
    sa[i]=i;
    if(i<n){
      rk[i]=s[i]-'0';
    }else{
      rk[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]];
      if(compare_sa(sa[i-1], sa[i])) tmp[sa[i]]++;
    }
    for(int i=0; i<=n; i++) rk[i]=tmp[i];
  }
}

int main()
{
	ll h;
  cin>>n>>h;
  string s;
  cin>>s;
  ll w[100001]={}, ws[100001];
  ws[0]=0;
  ll ct=0;
  ll z=0;
  for(int i=0; i<n; i++){
    if(s[i]=='0'){
      ct++;
    }else{
      w[i]=ct+1;
      z+=ct*(ct+1)/2;
      ct=0;
    }
  }
  w[n]=ct+1;
  z+=ct*(ct+1)/2;
  if(h<=z){
    cout<<0<<endl;
    return 0;
  }
  ws[0]=0;
  for(int i=1; i<=n; i++) ws[i]=ws[i-1]+w[i-1];
  h-=z;
  int sa[100001];
  construct_sa(s, sa);
  //for(int i=0; i<=n; i++) cout<<sa[i]<<" ";
  //cout<<endl;
  for(int d=1; d<=n; d++){
    if(ws[n-d+1]<h){
      h-=ws[n-d+1];
      continue;
    }
    for(int i=1; i<=n; i++){
      if(sa[i]>n-d || s[sa[i]]=='0') continue;
      if(h<=w[sa[i]]){
        for(int j=0; j<d; j++) cout<<s[sa[i]+j];
        cout<<endl;
        return 0;
      }
      h-=w[sa[i]];
    }
  }
	return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 5992
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;

struct SuffixArray{
  Int n,k;
  string S;
  vector<Int> sa,lcp;
  SuffixArray(){}
  SuffixArray(string& S):S(S){init();}
  void init(){
    n=S.length();
    S.push_back('$');
    build_sa();
  }
  void build_sa(){
    sa.clear();
    sa.resize(n+1,0);
    iota(sa.begin(),sa.end(),0);
    sort(sa.begin(),sa.end(),
	 [&](Int a,Int b){
	   if(S[a]==S[b]) return a>b;
	   return S[a]<S[b];
	 });
    vector<Int> c(n+1,0),r(n+1),cnt(n+1),s(n+1);
    for(Int i=0;i<=n;i++) r[i]=S[i];
    for(Int len=1;len<=n;len*=2){
      for(Int i=0;i<=n;i++){
	 c[sa[i]]=
	   i>0 &&
	   r[sa[i-1]]==r[sa[i]] &&
	   sa[i-1]+len<=n &&
	   r[sa[i-1]+len/2]==r[sa[i]+len/2] ?
	   c[sa[i-1]]:i;
      }
      iota(cnt.begin(),cnt.end(),0);
      copy(sa.begin(),sa.end(),r.begin());
      for(Int i=0;i<=n;i++){
	Int s1=r[i]-len;
	if(s1>=0) sa[cnt[c[s1]]++]=s1;
      }
      c.swap(r);
    }
  }
};

//INSERT ABOVE HERE
signed main(){
  Int n,k;
  string s;
  cin>>n>>k>>s;
  auto calc=[](Int x){return x*(x+1)/2;};
  Int zs=0;
  vector<Int> cnt(n+1,1);
  for(Int i=0;i<n;i++){
    if(s[i]=='0'){
      if(i+1>=n||s[i+1]!='0') zs+=calc(cnt[i]);
      if(i+1<n) cnt[i+1]+=cnt[i];
      cnt[i]=0;
    }
  }
  if(k<=zs){
    cout<<0<<endl;
    return 0;
  }
  k-=zs+1;
  vector<Int> sum(n+1,0);
  for(Int i=0;i<n;i++) sum[i+1]=sum[i]+cnt[i];
  Int len=1;
  while(k>=sum[n+1-len]&&len<n) k-=sum[n+1-(len++)];
  SuffixArray sa(s);
  Int pos=0;
  for(Int i=1;i<=n;i++){
    if(s[sa.sa[i]]=='0'||sa.sa[i]+len>n) continue;
    //cout<<len<<" "<<i<<" "<<k<<endl;
    if(k>=0) pos=sa.sa[i];
    k-=cnt[sa.sa[i]];
  }
  cout<<s.substr(pos,len)<<endl;
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 8460
final_rank: 10

code_snippet: #include <iostream>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;

struct SuffixArray {
    int N, k;
    vector<int> rank, sa;
    string s;

    SuffixArray(string t) {
        s = t, k = 1, N = t.length();
        rank = sa = vector<int>(N+1);
        build();
    }

    bool compare_sa(int i, int j) {
        if(rank[i] != rank[j]) return rank[i] < rank[j];
        else {
            int vi = (i+k <= N ? rank[i+k] : -1);
            int vj = (j+k <= N ? rank[j+k] : -1);
            return vi < vj;
        }
    }

    void build() {
        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.begin(), sa.end(), [&](int i, int j) {
                return compare_sa(i, j);
            });

            vector<int> tmp(N+1, 0);
            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);
            }

            swap(rank, tmp);
        }
    }

    string get_substr(int idx) {
        return s.substr(sa[idx]);
    }

    void output() {
        for(int i=0; i<=N; i++) {
            fprintf(stderr, "idx = %d, str = %s\n", i, get_substr(i).c_str());
        }
    }

    int operator[](int idx) const {
        return sa[idx];
    }
};

const int SIZE = 1 << 17;
struct segtree {
    long long int node[2*SIZE];
    segtree() {
        fill(node, node+2*SIZE, 0);
    }
    void update(int idx, long long int val) {
        idx += SIZE - 1;
        node[idx] += val;
        while(idx > 0) {
            idx = (idx - 1) / 2;
            node[idx] = node[2*idx+1] + node[2*idx+2];
        }
    }
    long long int query(int a, int b, int l=0, int r=SIZE, int k=0) {
        if(b <= l || r <= a) return 0;
        if(a <= l && r <= b) return node[k];
        int mid = (l + r) / 2;
        long long int vl = query(a, b, l, mid, 2*k+1);
        long long int vr = query(a, b, mid, r, 2*k+2);
        return vl + vr;
    }
};

segtree seg;
int main() {
    int N;
    long long int H; cin >> N >> H;

    string s; cin >> s;
    SuffixArray suf(s);
    // suf.output();

    int len = s.length(), cnt_zero = 0;
    vector<long long int> weight(len);
    for(size_t i=0; i<s.length(); i++) {
        if(s[i] == '0') {
            cnt_zero++;
            H -= cnt_zero;
        }
        else {
            weight[i] = cnt_zero + 1;
            // printf("weight[%zu] = %d\n", i, weight[i]);
            cnt_zero = 0;
        }
    }

    if(H <= 0) {
        cout << 0 << endl;
        return 0;
    }
    else {
        vector<int> order;
        for(int i=0; i<=len; i++) {
            if(suf[i] >= len || s[ suf[i] ] == '0') continue;
            else {
                order.push_back(i);
            }
        }

        vector<int> end_point[100010];
        for(auto x : order) {
            seg.update(x, weight[ suf[x] ]);
            // printf("pos = %d, end_point = %d, weight = %lld\n", x, N-suf[x], weight[ suf[x] ]);
            end_point[N - suf[x]].push_back(x);
        }

        int step = 1;
        for(; H > seg.query(0, len+1); step++) {
            H -= seg.query(0, len+1);
            for(auto v : end_point[step]) {
                seg.update(v, -weight[ suf[v] ]);
            }
        }

        int ub = len+1, lb = 0;
        while(ub - lb > 1) {
            int mid = (ub + lb) / 2;
            // printf("mid = %d, val = %lld\n", mid, seg.query(0, mid));
            if(H <= seg.query(0, mid)) ub = mid;
            else lb = mid;
        }

        // printf("H = %lld, lb = %d, step = %d\n", H, lb, step);
        cout << s.substr(suf[lb], step) << endl;
    }
}
accuracy: 1
time_ms: 80
memory_kb: 12452
final_rank: 16

code_snippet: #include "bits/stdc++.h"
using namespace std;
#define rep(i,n) for (int i=0;i<(n);i++)
#define rep2(i,a,b) for (int i=(a);i<(b);i++)

using ll = long long;
using Pll = pair<ll, ll>;

class SuffixArray {
private:
    string s;
    int n;
    vector<int> rank;
    vector<int> sa;
public:
    SuffixArray(string _s) : s(_s) {
        n = s.size();
        rank.resize(n + 1);
        sa.resize(n + 1);
        construct();
    }
    vector<int> construct() {
        for (int i = 0; i <= n; ++i) {
            sa[i] = i;
            rank[i] = i < n ? s[i] : -1;
        }

        int k;
        auto compare = [&](int i, int j) {
            if (rank[i] != rank[j]) return rank[i] < rank[j];
            else {
                int ri = i + k <= n ? rank[i + k] : -1;
                int rj = j + k <= n ? rank[j + k] : -1;
                return ri < rj;
            }
        };

        vector<int> tmp(n + 1);
        for (k = 1; k <= n; k *= 2) {
            sort(sa.begin(), sa.end(), compare);

            tmp[sa[0]] = 0;
            for (int i = 1; i <= n; ++i) {
                tmp[sa[i]] = tmp[sa[i - 1]] + (compare(sa[i - 1], sa[i]) ? 1 : 0);
            }
            for (int i = 0; i <= n; ++i) {
                rank[i] = tmp[i];
            }
        }
        return sa;
    }
};

int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(0);

  int n;
  ll k;
  cin >> n >> k;
  string s;
  cin >> s;
  vector<ll> lead(n + 1); // leading zero
  rep2(i, 1, n + 1) {
    if (s[i - 1] == '0') {
      lead[i] = lead[i - 1] + 1;
    }
  }

  ll num_zero = accumulate(lead.begin(), lead.end(), 0ll);
  k -= num_zero;
  if (k <= 0) {
    cout << 0 << endl;
    return 0;
  }

  auto f = [&](ll m) {
    ll a = 0;
    rep(i, n) {
      if (s[i] != '0') {
        a += (lead[i] + 1) * min<ll>(n - i, m);
      }
    }
    return a;
  };

  ll l = 0, r = n;
  while (r - l > 1) {
    ll m = (l + r) / 2;
    if (k <= f(m)) r = m;
    else l = m;
  }

  ll len = r;
  ll kk = k - f(len - 1);
  SuffixArray suf(s);
  vector<int> sa = suf.construct();
  rep2(i, 1, sa.size()) {
    if (sa[i] == n || s[sa[i]] == '0' || n - sa[i] < len) continue;
    int num = lead[sa[i]] + 1;
    kk -= num;
    if (kk <= 0) {
      cout << s.substr(sa[i], len) << endl;
      return 0;
    }
  }
}
accuracy: 1
time_ms: 110
memory_kb: 5516
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

vector<ll> suffix_array(const string &S) {
  ll n = S.length(), k = 1;
  vector<ll> sa(n + 1), rnk(n + 1), tmp(n + 1);

  auto compare_sa = [&](ll i, ll j) {
    if(rnk[i] != rnk[j]) return rnk[i] < rnk[j];
    ll ri = i + k <= n ? rnk[i + k] : -1;
    ll rj = j + k <= n ? rnk[j + k] : -1;
    return ri < rj;
  };

  REP(i, 0, n + 1) sa[i] = i;
  REP(i, 0, n + 1) rnk[i] = i < n ? S[i] : -1;

  for(; k <= n; k *= 2) {
    sort(sa.begin(), sa.end(), compare_sa);
    tmp[sa[0]] = 0;
    REP(i, 1, n + 1) tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    REP(i, 0, n + 1) rnk[i] = tmp[i];
  }

  return sa;
}

int main(void) {
  ll N, H;
  string S;
  cin >> N >> H >> S;

  vector<ll> a(N, 0);
  REP(i, 0, N - 1) if(S[i] == '0') a[i + 1] += a[i] + 1;

  vector<ll> imos(N + 2, 0);
  REP(i, 0, N) {
    if(S[i] != '0') {
      imos[1] += a[i] + 1;
      imos[N - i + 1] -= a[i] + 1;
    } else {
      imos[1] += a[i] + 1;
      imos[2] -= a[i] + 1;
    }
  }
  REP(i, 0, N + 1) imos[i + 1] += imos[i];

  ll x = 1, cnt = 1;
  while(1) {
    if(cnt <= H && H < cnt + imos[x]) break;
    cnt += imos[x];
    x++;
  }

  vector<ll> sa = suffix_array(S);
  REP(i, 1, N + 1) {
    ll j = sa[i];
    if((x == 1 || S[j] != '0') && j + x <= N) {
      if(cnt <= H && H < cnt + a[j] + 1) {
        cout << S.substr(j, x) << endl;
        break;
      }
      cnt += a[j] + 1;
    }
  }
}
accuracy: 1
time_ms: 60
memory_kb: 6908
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

vector<ll> construct_suffix_array(const string &S) {
  ll n = S.length(), k = 1;
  vector<ll> sa(n + 1), rnk(n + 1), tmp(n + 1);

  auto compare_sa = [&](const ll& i, const ll& j) {
    if(rnk[i] != rnk[j]) return rnk[i] < rnk[j];
    ll ri = i + k <= n ? rnk[i + k] : -1;
    ll rj = j + k <= n ? rnk[j + k] : -1;
    return ri < rj;
  };

  REP(i, 0, n + 1) sa[i] = i;
  REP(i, 0, n + 1) rnk[i] = i < n ? S[i] : -1;

  for(; k <= n; k *= 2) {
    sort(sa.begin(), sa.end(), compare_sa);
    tmp[sa[0]] = 0;
    REP(i, 1, n + 1) tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    REP(i, 0, n + 1) rnk[i] = tmp[i];
  }

  return sa;
}

int main(void) {
  ll N, H;
  string S;
  cin >> N >> H >> S;

  vector<ll> a(N, 0);
  REP(i, 0, N - 1) if(S[i] == '0') a[i + 1] += a[i] + 1;

  vector<ll> imos(N + 2, 0);
  REP(i, 0, N) {
    if(S[i] != '0') {
      imos[1] += a[i] + 1;
      imos[N - i + 1] -= a[i] + 1;
    } else {
      imos[1] += a[i] + 1;
      imos[2] -= a[i] + 1;
    }
  }
  REP(i, 0, N + 1) imos[i + 1] += imos[i];

  ll x = 1, cnt = 1;
  while(1) {
    if(cnt <= H && H < cnt + imos[x]) break;
    cnt += imos[x];
    x++;
  }

  vector<ll> sa = construct_suffix_array(S);
  REP(i, 1, N + 1) {
    ll j = sa[i];
    if((x == 1 || S[j] != '0') && j + x <= N) {
      if(cnt <= H && H < cnt + a[j] + 1) {
        cout << S.substr(j, x) << endl;
        break;
      }
      cnt += a[j] + 1;
    }
  }
}
accuracy: 1
time_ms: 60
memory_kb: 6880
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

vector<ll> construct_suffix_array(const string &S) {
  ll n = S.length(), k = 1;
  vector<ll> sa(n + 1), rnk(n + 1), tmp(n + 1);

  auto compare_sa = [&](const ll &i, const ll &j) {
    if(rnk[i] != rnk[j]) return rnk[i] < rnk[j];
    ll ri = i + k <= n ? rnk[i + k] : -1;
    ll rj = j + k <= n ? rnk[j + k] : -1;
    return ri < rj;
  };

  REP(i, 0, n + 1) sa[i] = i;
  REP(i, 0, n + 1) rnk[i] = i < n ? S[i] : -1;

  for(; k <= n; k *= 2) {
    sort(sa.begin(), sa.end(), compare_sa);
    tmp[sa[0]] = 0;
    REP(i, 1, n + 1) tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    REP(i, 0, n + 1) rnk[i] = tmp[i];
  }

  return sa;
}

int main(void) {
  ll N, H;
  string S;
  cin >> N >> H >> S;

  vector<ll> a(N, 0);
  REP(i, 0, N - 1) if(S[i] == '0') a[i + 1] += a[i] + 1;

  vector<ll> imos(N + 2, 0);
  REP(i, 0, N) {
    if(S[i] != '0') {
      imos[1] += a[i] + 1;
      imos[N - i + 1] -= a[i] + 1;
    } else {
      imos[1] += a[i] + 1;
      imos[2] -= a[i] + 1;
    }
  }
  REP(i, 0, N + 1) imos[i + 1] += imos[i];

  ll x = 1, cnt = 1;
  while(1) {
    if(cnt <= H && H < cnt + imos[x]) break;
    cnt += imos[x];
    x++;
  }

  vector<ll> sa = construct_suffix_array(S);
  REP(i, 1, N + 1) {
    ll j = sa[i];
    if((x == 1 || S[j] != '0') && j + x <= N) {
      if(cnt <= H && H < cnt + a[j] + 1) {
        cout << S.substr(j, x) << endl;
        break;
      }
      cnt += a[j] + 1;
    }
  }
}
accuracy: 1
time_ms: 60
memory_kb: 6908
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define REP(i, a, n) for(ll i ((ll) a); i < ((ll) n); i++)
using namespace std;
typedef long long ll;

const ll MAX_N = 500000;
ll n, k;
ll rnk[MAX_N + 1];
ll tmp[MAX_N + 1];

bool compare_sa(ll i, ll j) {
  if(rnk[i] != rnk[j]) return rnk[i] < rnk[j];
  ll ri = i + k <= n ? rnk[i + k] : -1;
  ll rj = j + k <= n ? rnk[j + k] : -1;
  return ri < rj;
}

vector<ll> construct_sa(const string &S) {
  n = S.length();
  vector<ll> sa(n + 1);
  REP(i, 0, n + 1) sa[i] = i;
  REP(i, 0, n + 1) rnk[i] = i < n ? S[i] : -1;
  for(k = 1; k <= n; k *= 2) {
    sort(sa.begin(), sa.end(), compare_sa);
    tmp[sa[0]] = 0;
    REP(i, 1, n + 1) tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    REP(i, 0, n + 1) rnk[i] = tmp[i];
  }
  return sa;
}

int main(void) {
  ll N, H;
  string S;
  cin >> N >> H >> S;

  vector<ll> a(N, 0);
  REP(i, 0, N - 1) if(S[i] == '0') a[i + 1] += a[i] + 1;

  vector<ll> imos(N + 2, 0);
  REP(i, 0, N) {
    if(S[i] != '0') {
      imos[1] += a[i] + 1;
      imos[N - i + 1] -= a[i] + 1;
    } else {
      imos[1] += a[i] + 1;
      imos[2] -= a[i] + 1;
    }
  }
  REP(i, 0, N + 1) imos[i + 1] += imos[i];

  ll x = 1, cnt = 1;
  while(1) {
    if(cnt <= H && H < cnt + imos[x]) break;
    cnt += imos[x];
    x++;
  }

  vector<ll> sa = construct_sa(S);
  REP(i, 1, N + 1) {
    ll j = sa[i];
    if((x == 1 || S[j] != '0') && j + x <= N) {
      if(cnt <= H && H < cnt + a[j] + 1) {
        cout << S.substr(j, x) << endl;
        break;
      }
      cnt += a[j] + 1;
    }
  }
}
accuracy: 1
time_ms: 80
memory_kb: 6916
final_rank: 13

code_snippet: #include <bits/stdc++.h>

using namespace std;

struct SuffixArray {
  vector< int > SA;
  string s;

  void Build_SA(const string &str) {
    s = str;
    SA.resize(s.size());
    iota(begin(SA), end(SA), 0);
    sort(begin(SA), end(SA), [&](const int &a, const int &b) {
      if(s[a] == s[b]) return (a > b);
      return (s[a] < s[b]);
    });
    vector< int > classes(s.size()), c(s.size()), cnt(s.size());
    for(int i = 0; i < s.size(); i++) {
      c[i] = s[i];
    }
    for(int len = 1; len < s.size(); len <<= 1) {
      for(int i = 0; i < s.size(); i++) {
        if(i > 0 && c[SA[i - 1]] == c[SA[i]] && SA[i - 1] + len < s.size() && c[SA[i - 1] + len / 2] == c[SA[i] + len / 2]) {
          classes[SA[i]] = classes[SA[i - 1]];
        } else {
          classes[SA[i]] = i;
        }
      }
      iota(begin(cnt), end(cnt), 0);
      copy(begin(SA), end(SA), begin(c));
      for(int i = 0; i < s.size(); i++) {
        int s1 = c[i] - len;
        if(s1 >= 0) SA[cnt[classes[s1]]++] = s1;
      }
      classes.swap(c);
    }
  }

  int operator[](int k) const {
    return (SA[k]);
  }

  int size() const {
    return (s.size());
  }

  bool lt_substr(string &t, int si = 0, int ti = 0) {
    int sn = s.size(), tn = t.size();
    while(si < sn && ti < tn) {
      if(s[si] < t[ti]) return (true);
      if(s[si] > t[ti]) return (false);
      ++si, ++ti;
    }
    return (si >= sn && ti < tn);
  }

  int lower_bound(string &t) {
    int low = -1, high = SA.size();
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    return (high);
  }

  pair< int, int > lower_upper_bound(string &t) {
    int idx = lower_bound(t);
    int low = idx - 1, high = SA.size();
    t.back()++;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    t.back()--;
    return (make_pair(idx, high));
  }

  void output() {
    for(int i = 0; i < size(); i++) {
      cout << i << ": " << s.substr(SA[i]) << endl;
    }
  }
};

using int64 = long long;

template< class T >
struct BinaryIndexedTree {
  vector< T > data;

  BinaryIndexedTree(int sz) {
    data.assign(++sz, 0);
  }

  T sum(int k) {
    T ret = 0;
    for(++k; k > 0; k -= k & -k) ret += data[k];
    return (ret);
  }

  void add(int k, T x) {
    for(++k; k < data.size(); k += k & -k) data[k] += x;
  }
};

template< class T >
struct AdditionalBIT : BinaryIndexedTree< T > {
  int curr;

  AdditionalBIT(int sz) : BinaryIndexedTree< T >(sz) {
    curr = 1;
    while(curr <= sz) curr <<= 1;
  }

  int lower_bound(T w) {
    if(w <= 0) return (0);
    int i = 0;
    for(int k = curr; k > 0; k >>= 1) {
      if(i + k < BinaryIndexedTree< T >::data.size() && BinaryIndexedTree< T >::data[i + k] < w) {
        w -= BinaryIndexedTree< T >::data[i + k];
        i += k;
      }
    }
    return (i);
  }
};

int main() {
  int64 N, H;
  string S;

  cin >> N >> H;
  cin >> S;

  int wait = 0;
  vector< int > weight(S.size());
  for(int i = 0; i < S.size(); i++) {
    if(S[i] == '0') {
      ++wait;
      H -= wait;
    } else {
      weight[i] += wait + 1;
      wait = 0;
    }
  }

  SuffixArray sa;
  sa.Build_SA(S);

  if(H <= 0) {
    cout << 0 << endl;
    return (0);
  }

  vector< int > order;
  for(int i = 0; i < S.size(); i++) {
    if(S[sa[i]] == '0') continue;
    order.emplace_back(i);
  }

  AdditionalBIT< int64 > bit(N);
  vector< int > end[100001];
  for(auto &v : order) {
    bit.add(v, weight[sa[v]]);
    end[N - sa[v]].emplace_back(v);
  }

  int keta = 1;
  for(; H - bit.sum(N - 1) >= 1; ++keta) {
    H -= bit.sum(N - 1);
    for(auto &p : end[keta]) bit.add(p, -weight[sa[p]]);
  }

  cout << S.substr(sa[bit.lower_bound(H)], keta) << endl;
}
accuracy: 1
time_ms: 40
memory_kb: 10360
final_rank: 15

code_snippet: #include <bits/stdc++.h>

using namespace std;

struct SuffixArray {
  vector< int > SA;
  string s;

  void Build_SA(const string &str) {
    s = str;
    SA.resize(s.size());
    iota(begin(SA), end(SA), 0);
    sort(begin(SA), end(SA), [&](const int &a, const int &b) {
      if(s[a] == s[b]) return (a > b);
      return (s[a] < s[b]);
    });
    vector< int > classes(s.size()), c(s.size()), cnt(s.size());
    for(int i = 0; i < s.size(); i++) {
      c[i] = s[i];
    }
    for(int len = 1; len < s.size(); len <<= 1) {
      for(int i = 0; i < s.size(); i++) {
        if(i > 0 && c[SA[i - 1]] == c[SA[i]] && SA[i - 1] + len < s.size() && c[SA[i - 1] + len / 2] == c[SA[i] + len / 2]) {
          classes[SA[i]] = classes[SA[i - 1]];
        } else {
          classes[SA[i]] = i;
        }
      }
      iota(begin(cnt), end(cnt), 0);
      copy(begin(SA), end(SA), begin(c));
      for(int i = 0; i < s.size(); i++) {
        int s1 = c[i] - len;
        if(s1 >= 0) SA[cnt[classes[s1]]++] = s1;
      }
      classes.swap(c);
    }
  }

  int operator[](int k) const {
    return (SA[k]);
  }

  int size() const {
    return (s.size());
  }

  bool lt_substr(string &t, int si = 0, int ti = 0) {
    int sn = s.size(), tn = t.size();
    while(si < sn && ti < tn) {
      if(s[si] < t[ti]) return (true);
      if(s[si] > t[ti]) return (false);
      ++si, ++ti;
    }
    return (si >= sn && ti < tn);
  }

  int lower_bound(string &t) {
    int low = -1, high = SA.size();
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    return (high);
  }

  pair< int, int > lower_upper_bound(string &t) {
    int idx = lower_bound(t);
    int low = idx - 1, high = SA.size();
    t.back()++;
    while(high - low > 1) {
      int mid = (low + high) >> 1;
      if(lt_substr(t, SA[mid])) low = mid;
      else high = mid;
    }
    t.back()--;
    return (make_pair(idx, high));
  }

  void output() {
    for(int i = 0; i < size(); i++) {
      cout << i << ": " << s.substr(SA[i]) << endl;
    }
  }
};

using int64 = long long;

template< class T >
struct BinaryIndexedTree {
  vector< T > data;

  BinaryIndexedTree(int sz) {
    data.assign(++sz, 0);
  }

  T sum(int k) {
    T ret = 0;
    for(++k; k > 0; k -= k & -k) ret += data[k];
    return (ret);
  }

  void add(int k, T x) {
    for(++k; k < data.size(); k += k & -k) data[k] += x;
  }
};

template< class T >
struct AdditionalBIT : BinaryIndexedTree< T > {
  int curr;

  AdditionalBIT(int sz) : BinaryIndexedTree< T >(sz) {
    curr = 1;
    while(curr <= sz) curr <<= 1;
  }

  int lower_bound(T w) {
    if(w <= 0) return (0);
    int i = 0;
    for(int k = curr; k > 0; k >>= 1) {
      if(i + k < BinaryIndexedTree< T >::data.size() && BinaryIndexedTree< T >::data[i + k] < w) {
        w -= BinaryIndexedTree< T >::data[i + k];
        i += k;
      }
    }
    return (i);
  }
};

int main() {
  int N, H;
  string S;

  cin >> N >> H;
  cin >> S;

  int wait = 0;
  vector< int > weight(S.size());
  for(int i = 0; i < S.size(); i++) {
    if(S[i] == '0') {
      ++wait;
      H -= wait;
    } else {
      weight[i] += wait + 1;
      wait = 0;
    }
  }

  SuffixArray sa;
  sa.Build_SA(S);

  if(H <= 0) {
    cout << 0 << endl;
    return (0);
  }

  vector< int > order;
  for(int i = 0; i < S.size(); i++) {
    if(S[sa[i]] == '0') continue;
    order.emplace_back(i);
  }

  AdditionalBIT< int64 > bit(N);
  vector< int > end[100001];
  for(auto &v : order) {
    bit.add(v, weight[sa[v]]);
    end[N - sa[v]].emplace_back(v);
  }

  int keta = 1;
  for(; H - bit.sum(N - 1) >= 1; ++keta) {
    H -= bit.sum(N - 1);
    for(auto &p : end[keta]) bit.add(p, -weight[sa[p]]);
  }

  cout << S.substr(sa[bit.lower_bound(H)], keta) << endl;
}
accuracy: 0.6779661016949152
time_ms: 20
memory_kb: 8264
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcount

#define INF 1e16
#define mod 1000000007

int _n,_k;
int ranks[101010];
int tmp[101010];

bool compare_sa(int i,int j){
  if(ranks[i]!=ranks[j])return ranks[i]<ranks[j];
  else{
    int ri=i+_k<=_n?ranks[i+_k]:-1;
    int rj=j+_k<=_n?ranks[j+_k]:-1;
    return ri<rj;
  }
}
void construct_sa(string s,int *sa){
  _n=s.length();
  for(int i=0;i<=_n;i++){
    sa[i]=i;
    ranks[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++){
      ranks[i]=tmp[i];
    }
  }
}

ll n,h;
string s;
ll cnt[101010];
int sa[101010];
ll sum[101010];

int main(){
  cin>>n>>h>>s;
  for(ll i=0;i<n;){
    if(s[i]!='0'){
      sum[i]++;
      ll suf=n-i;
      cnt[1]++;
      cnt[suf+1]--;
      i++;
      continue;
    }
    ll j;
    for(j=i;j<n&&s[j]=='0';j++);
    ll len=j-i;
    ll suf=n-j;
    sum[j]+=len;
    cnt[0]+=len*(len+1)/2;
    cnt[1]+=len;
    cnt[suf+1]-=len;
    i=j;
  }

  for(ll i=1;i<100001;i++)cnt[i+1]+=cnt[i];

  construct_sa(s,sa);

  if(h<=cnt[0]){
    cout<<0<<endl;
  }else{
    h-=cnt[0];
    ll d=-1;
    repl(i,1,n+1){
      if(h<=cnt[i]){
        d=i;
        break;
      }else h-=cnt[i];
    }
    repl(i,1,n+1){
      if(n-sa[i]>=d&&s[sa[i]]!='0'){
        if(h<=sum[sa[i]]){
          cout<<s.substr(sa[i],d)<<endl;
          return 0;
        }else h-=sum[sa[i]];
      }
    }
  }

  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 5964
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define _MACRO(_1, _2, _3, NAME, ...) NAME
#define _repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define _rep(i,n) _repl(i,0,n)
#define rep(...) _MACRO(__VA_ARGS__, _repl, _rep)(__VA_ARGS__)
#define mp make_pair
#define pb push_back
#define all(x) begin(x),end(x)
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cerr<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cerr<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream &o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream &o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

typedef long long ll;
typedef pair<int,int> P;

class SuffixArray {
public:
  const string &s;
  vector<int> sa, rank;
  int n;
  void construct_sa(){
    sa.resize(n+1);
    rank.resize(n+1);
    rep(i,n+1){
      sa[i]=i;
      rank[i] = (i<n)?s[i]:(-1);
    }
    vector<int> tmp(n+1,0);
    for(int k=1; k<=n; k*=2){
      auto comp = [&](const int i, const 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;
      };
      sort(all(sa), comp);
      tmp[sa[0]]=0;
      rep(i,1,n+1){
        tmp[sa[i]] = tmp[sa[i-1]];
        if(comp(sa[i-1], sa[i])) tmp[sa[i]]++;
      }
      swap(tmp, rank);
    }
  }
  SuffixArray(const string &str) : s(str){
    n = s.size();
    construct_sa();
  }
};


void solve(int n, ll h, string &str, int len){
  if(len == 0){
    cout << "0" << endl;
    return;
  }

  SuffixArray sa(str);
  vector<int> arr(n+1,0);
  rep(i,1,n+1) if(str[sa.sa[i]]>'0'){
    int idx = sa.sa[i];
    int d = 1;
    if(n-idx < len) d = 0;
    else {
      while(idx-d>=0 && str[idx-d]=='0') d++;
    }
    arr[i] = arr[i-1] + d;
    if(arr[i] >= h){
      cout << str.substr(idx, len) << endl;
      return;
    }
  }
  assert(false);
}

int main(void){
	int n;
	ll h;
	string str;
	scanf("%d%lld",&n,&h);
	cin >> str;
	int z=-1;
	vector<int> nonzero(n+1);
	vector<ll> cnt(n+1);
	for(int i=0;i<=n;i++){
		cnt[i]=0;
	}
	for(int i=n-1;i>=0;i--){
		if(str[i]>='1'){
			z=i;
		}
		nonzero[i]=z;
	}
	for(int i=0;i<n;i++){
		//printf("%d\n",nonzero[i]);
		if(nonzero[i]==-1)continue;
		cnt[n-nonzero[i]]++;
	}
	for(int i=n;i>1;i--){
		cnt[i-1]+=cnt[i];
	}
	ll len=0;
	for(int i=0;i<n;i++){
		if(str[i]=='0'){
			len++;
		}else{
			cnt[0]+=len*(len+1)/2LL;
			len=0;
		}
	}
	cnt[0]+=len*(len+1)/2LL;
	ll sum=0;
	for(int i=0;i<=n;i++){
		sum+=cnt[i];
		if(sum>=h){
			sum-=cnt[i];
			solve(n,h-sum,str,i);
			return 0;
		}
	}
	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 5472
final_rank: 3

code_snippet: #include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long lint;
typedef vector<int>vi;
typedef pair<int,int>pii;
#define rep(i,n)for(int i=0;i<(int)(n);++i)
#define REP(i,n) for(int i=0;i<(int)n;++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

const int DEBUG=0;

// http://www.prefield.com/algorithm/string/suffix_array.html

// Larsson-Sadakane's Suffix array Construction: O(n (log n)^2)
struct SAComp {
  const int h, *g;
  SAComp(int h, int* g) : h(h), g(g) {}
  bool operator() (int a, int b) {
    return a == b ? false : g[a] != g[b] ? g[a] < g[b] : g[a+h] < g[b+h];
  }
};
int *buildSA(const char* t, int n) {
  int g[n+1], b[n+1], *v = new int[n+1];
  REP(i,n+1) v[i] = i, g[i] = t[i];
  b[0] = 0; b[n] = 0;

  sort(v, v+n+1, SAComp(0, g));
  for(int h = 1; b[n] != n ; h *= 2) {
    SAComp comp(h, g);
    sort(v, v+n+1, comp);
    REP(i, n) b[i+1] = b[i] + comp(v[i], v[i+1]);
    REP(i, n+1) g[v[i]] = b[i];
  }
  return v;
}
// Naive matching O(m log n)
int find(char *t, int n, char *p, int m, int *sa) {
  int a = 0, b = n;
  while (a < b) {
    int c = (a + b) / 2;
    if (strncmp(t+sa[c], p, m) < 0) a = c+1; else b = c;
  }
  return strncmp(t+sa[a], p, m) == 0 ? sa[a] : -1;
}

// Kasai-Lee-Arimura-Arikawa-Park's simple LCP computation: O(n)
int *buildLCP(char *t, int n, int *a) {
  int h = 0, b[n+1], *lcp = new int[n+1];
  REP(i, n+1) b[a[i]] = i;
  REP(i, n+1) {
    if (b[i]){
      for (int j = a[b[i]-1]; j+h<n && i+h<n && t[j+h] == t[i+h]; ++h);
      lcp[b[i]] = h;
    } else lcp[b[i]] = -1;
    if (h > 0) --h;
  }
  return lcp;
}
// call RMQ = buildRMQ(lcp, n+1)
int *buildRMQ(int *a, int n) {
  int logn = 1;
  for (int k = 1; k < n; k *= 2) ++logn;
  int *r = new int[n * logn];
  int *b = r; copy(a, a+n, b);
  for (int k = 1; k < n; k *= 2) {
    copy(b, b+n, b+n); b += n;
    REP(i, n-k) b[i] = min(b[i], b[i+k]);
  }
  return r;
}
// inner LCP computation with RMQ: O(1)
int minimum(int x, int y, int *rmq, int n) {
  int z = y - x, k = 0, e = 1, s; // y - x >= e = 2^k なる最大 k
  s = ( (z & 0xffff0000) != 0 ) << 4; z >>= s; e <<= s; k |= s;
  s = ( (z & 0x0000ff00) != 0 ) << 3; z >>= s; e <<= s; k |= s;
  s = ( (z & 0x000000f0) != 0 ) << 2; z >>= s; e <<= s; k |= s;
  s = ( (z & 0x0000000c) != 0 ) << 1; z >>= s; e <<= s; k |= s;
  s = ( (z & 0x00000002) != 0 ) << 0; z >>= s; e <<= s; k |= s;
  return min( rmq[x+n*k], rmq[y+n*k-e+1] );
}
// outer LCP computation: O(m - o)
int computeLCP(char *t, int n, char *p, int m, int o, int k) {
  int i = o;
  for (; i < m && k+i < n && p[i] == t[k+i]; ++i);
  return i;
}
// Mamber-Myers's O(m + log n) string matching with LCP/RMQ
#define COMP(h, k) (h == m || (k+h<n && p[h]<t[k+h]))
int find(char *t, int n, char *p, int m, int *sa, int *rmq) {
  int l = 0, lh = 0, r = n, rh = computeLCP(t,n+1,p,m,0,sa[n]);
  if (!COMP(rh, sa[r])) return -1;
  for (int k = (l+r)/2; l+1 < r; k = (l+r)/2) {
    int A = minimum(l+1, k, rmq, n+1), B = minimum(k+1, r, rmq, n+1);
    if (A >= B) {
      if (lh < A) l = k;
      else if (lh > A) r = k, rh = A;
      else {
        int i = computeLCP(t, n+1, p, m, A, sa[k]);
        if (COMP(i, sa[k])) r = k, rh = i; else l = k, lh = i;
      }
    } else {
      if (rh < B) r = k;
      else if (rh > B) l = k, lh = B;
      else {
        int i = computeLCP(t, n+1, p, m, B, sa[k]);
        if (COMP(i, sa[k])) r = k, rh = i; else l = k, lh = i;
      }
    }
  }
  return rh == m ? sa[r] : -1;
}

int main(){
  int n;
  lint h;
  string s;
  cin>>n>>h>>s;
  vi multa(n+1);
  int cnt=0;
  rep(i,n+1){
    cnt++;
    if(i<n&&s[i]=='0'){
      multa[i]=0;
    }else{
      multa[i]=cnt;
      cnt=0;
    }
  }
  int lo=-1,hi=n;
  while(hi-lo>1){
    int x=(hi+lo)/2;
    lint cnt=0;
    rep(i,n+1){
      if(i<n)
	cnt+=(lint)min(x,n-i)*multa[i];
      cnt+=(lint)multa[i]*(lint)(multa[i]-1)/2;
    }
    if(cnt>=h)
      hi=x;
    else
      lo=x;
  }
  int *sa=buildSA(s.c_str(),n);
  if(DEBUG){
    rep(i,n+1){
      cerr<<"suf:"<<sa[i]<<" "<<s.substr(sa[i])<<endl;
    }
  }
  int len=hi;
  if(DEBUG)cerr<<"len="<<len<<endl;
  vi tak;
  rep(i,n+1){
    if(sa[i]<=n-len)tak.push_back(sa[i]);
  }
  lint base=0;
  rep(i,n+1){
    if(i<n)
      base+=(lint)min(len-1,n-i)*multa[i];
    base+=(lint)multa[i]*(lint)(multa[i]-1)/2;
  }
  if(len==0){
    cout<<0<<endl;
    return 0;
  }
  if(DEBUG)
    cerr<<"base="<<base<<endl;
  if(DEBUG){
    cerr<<"tak:";
    rep(i,tak.size()){
      cerr<<" "<<tak[i];
      //cerr<<" "<<s.substr(tak[i])<<endl;
    }
    cerr<<endl;
  }
  int tmp=0,idx=-1;
  rep(i,tak.size()){
    if(s[tak[i]]!='0'){
      tmp+=multa[tak[i]];
      if(tmp+base>=h){
	idx=tak[i];
	break;
      }
    }
  }
  cout<<s.substr(idx,len)<<endl;
}
accuracy: 1
time_ms: 50
memory_kb: 5052
final_rank: 1

code_snippet: //ランタイムエラーの原因が分からなかったので、もしやと思い、sortをstable_sortに書き換えたらAcceptedした。なぜsortではダメなのか、よくわからない…
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#define int long long
using namespace std;
typedef pair<int, int> P;

/*https://kimiyuki.net/blog/2016/04/09/arc-050-d/より引用*/
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
#define repeat_from(i,m,n) for (int i = (m); (i) < (n); ++(i))
vector<int> suffix_array(string const & s) {
    int n = s.length();
    vector<int> sa(n+1);
    vector<int> rank(n+1);
    repeat (i,n+1) {
        sa[i] = i;
        rank[i] = i < n ? s[i] : -1;
    }
    auto rankf = [&](int i) { return i <= n ? rank[i] : -1; };
    vector<int> nxt(n+1);
    for (int k = 1; k <= n; k <<= 1) {
        auto cmp = [&](int i, int j) { return make_pair(rank[i], rankf(i + k)) < make_pair(rank[j], rankf(j + k)); };
        sort(sa.begin(), sa.end(), cmp);
        nxt[sa[0]] = 0;
        repeat_from (i,1,n+1) {
            nxt[sa[i]] = nxt[sa[i-1]] + (cmp(sa[i-1], sa[i]) ? 1 : 0);
        }
        rank.swap(nxt);
    }
    return sa;
}
/*終わり*/

/*ローリングハッシュ https://odan3240.hatenablog.com/entry/2015/02/16/111938*/
struct RollingHash {
    typedef long long int_type;
    typedef pair<int_type,int_type> hash_type;

    int_type base1;
    int_type base2;
    int_type mod1;
    int_type mod2;
    vector<int_type> hash1;
    vector<int_type> hash2;
    vector<int_type> pow1;
    vector<int_type> pow2;

    RollingHash() : base1(1009), base2(1007), mod1(1000000007), mod2(1000000009) {}

    void init(const string &s) {
        int n = s.size();

        hash1.assign(n+1,0);
        hash2.assign(n+1,0);
        pow1.assign(n+1,1);
        pow2.assign(n+1,1);

        for(int i=0;i<n;i++) {
            hash1[i+1] = (hash1[i]+s[i]) * base1 % mod1;
            hash2[i+1] = (hash2[i]+s[i]) * base2 % mod2;
            pow1[i+1] = pow1[i] * base1 % mod1;
            pow2[i+1] = pow2[i] * base2 % mod2;
        }
    }

	//[l, r)のハッシュ値を返す
    hash_type get(int l,int r) {
        int_type t1 = ((hash1[r] - hash1[l] * pow1[r-l]) % mod1 + mod1) % mod1;
        int_type t2 = ((hash2[r] - hash2[l] * pow2[r-l]) % mod2 + mod2) % mod2;
        return make_pair(t1, t2);
    }
};
/*終わり*/

int n, h;
string s;
int rs[100001];
int imos[100005];	//imos[i] = i桁の数字が何個あるか
vector<int> sa;
vector<int> saInv;	//saInv[i] = sa[id] = iなるidを書いておく
RollingHash rh;

bool compare(const P &l, const P &r) {
	if (rh.get(l.first, l.second) == rh.get(r.first, r.second)) return true;
	if (saInv[l.first] < saInv[r.first]) return true;
	return false;
}

signed main() {
	int i;
	
	cin >> n >> h >> s;
	for (i = 0; i < n; i++) rs[i + 1] = rs[i] + (s[i] > '0');
	
	for (i = 0; i < n; i++) {
		int st = i, ed = n + 1, mid; //(st, ed]
		while (ed - st >= 2) {
			mid = (st + ed) / 2;
			if (rs[mid] - rs[i] >= 1) ed = mid;
			else st = mid;
		}
		if (s[i] == '0') { imos[0] += ed - i - 1; imos[1] -= ed - i - 1; }
		imos[1]++;
		imos[n + 2 - ed]--;
	}
	
	for (i = 0; i <= n + 1; i++) imos[i + 1] += imos[i];
	//cout << "imos:" << endl;
	//for (i = 0; i <= n; i++) cout << imos[i] << endl;
	//cout << "imos*" << endl;
	
	for (i = 0; i <= n; i++) {
		h -= imos[i];
		if (h <= 0) break;
	}
	
	int keta = i;		//答えはi桁。
	if (keta == 0) { cout << 0 << endl; return 0; }
	//cout << "keta, h = " << keta << ", " << h << endl;
	
	vector<P> kukan;	//答えの候補 … [l, r)
	
	for (i = 0; i < n; i++) {
		int st = i, ed = n + 1, mid; //(st, ed]
		while (ed - st >= 2) {
			mid = (st + ed) / 2;
			if (rs[mid] - rs[i] >= 1) ed = mid;
			else st = mid;
		}
		if (ed + keta - 1 <= n) {
			kukan.push_back(P(ed - 1, ed + keta - 1));
		}
	}
	
	//cout << "ソート前" << endl;
	//for (i = 0; i < kukan.size(); i++) { cout << kukan[i].first << " " << kukan[i].second << endl; }
	
	sa = suffix_array(s);
	saInv.resize(sa.size());
	for (i = 0; i < sa.size(); i++) saInv[sa[i]] = i;
	//for (i = 0; i < sa.size(); i++) { cout << "sa[" << i << "] = " << sa[i] << endl; }
	rh.init(s);
	//for (i = 0; i < n; i++) for (int j = 0; j < n; j++) cout << "[" << i << ", " << j << "] = " << rh.get(i, j).first << endl;
	
	//kukanをソートしたい。その比較関数にsuffix_array, ローリングハッシュを用いる.
	stable_sort(kukan.begin(), kukan.end(), compare);
	//cout << "ソート後" << endl;
	//for (i = 0; i < kukan.size(); i++) { cout << kukan[i].first << " " << kukan[i].second << endl; }
	
	//あとは、適当に答えるだけ。
	int id = (int)kukan.size() - 1 + h;
	bool flag = false;
	for (i = kukan[id].first; i < kukan[id].second; i++) {
		if (s[i] != '0') flag = true;
		if (flag) cout << s[i];
	}
	cout << endl;
	return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 11376
final_rank: 17