Language: C++

#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;
	string srcStr;
	vector<int> sa;

private:
	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;
				a = (aIdx < m_strLen) ? rank[aIdx] : -1;
				b = (bIdx < m_strLen) ? rank[bIdx] : -1;
				return a < b;
			}
		};

		// 最初は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]] + compare_sa(sa[j - 1], sa[j]);
			}
			rank = nextRank;
		}
	}

	// 文字列検索
	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;
	}
};

string getMidStr(const string &a, const string &b)
{
	string aveStr;
	REP(i, a.size()) {
		int aNum = a[i] - '0';
		int bNum = b[i] - '0';
		int sumNum = (aNum + bNum) / 2;
		aveStr += sumNum + '0';
	}
	return aveStr;
}
###
bool compExec(SuffixArray &sa, const string &mid, int subStrNum)
{
	vector<int> used(sa.m_strLen, false);

	int saIdx = sa.lower_bound(mid);
	int enaCnt = 0;
	for (int i = saIdx; i >= 0; i--) {
		int startIdx = sa.sa[i];
		int endIdx = min((int)sa.m_strLen, (int)(mid.size() + startIdx));
		if ((mid.size() + startIdx) != endIdx) {
			continue;
		}

		bool bRet = true;
		for (int j = startIdx; j < endIdx; j++) {
			if (used[j]) {
				bRet = false;
				break;
			}
		}
		if (bRet) {
			enaCnt++;
	 		fill(used.begin() + startIdx, used.begin() + endIdx, true);
		}
	}

	return (subStrNum <= enaCnt);
}

int main()
{
	int K;
	string S;
	cin >> K >> S;
	int subStrLen;
	int subStrNum;
	K++;
	if ((S.size() % K) == 0) {
		subStrLen = S.size() / K;
		subStrNum = K;
	} else {
		subStrLen = S.size() / K + 1;
		subStrNum = S.size() % K;
	}
	
	SuffixArray sa(S);
	string lb(subStrLen, '0');
	string lu(subStrLen, '9');
	string mid(subStrLen, '0');
	while (lb < lu) {
		mid = getMidStr(lb, lu);
		if (!compExec(sa, mid, subStrNum)) {
			lb = mid;
		} else {
			lu = mid;
		}
	}
	cout <<  lu << endl;	return 0;
}



Compiler output:
a.cc:175:1: error: stray '##' in program
  175 | ###
      | ^~
a.cc:175:3: error: stray '#' in program
  175 | ###
      |   ^