Cod sursa(job #2602504)

Utilizator Mihai145Oprea Mihai Adrian Mihai145 Data 17 aprilie 2020 10:19:34
Problema Substr Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.5 kb
#include <iostream>
#include <cstring>
#include <vector>

using namespace std;

const int NMAX = 16384;
int N, K;
char s[NMAX + 2];

struct sufix
{
	int startingPos;
	pair <int, int> rnk;
};

sufix v[NMAX + 2], aux[NMAX + 2];
int count[NMAX + 2], newRank[NMAX + 2], posv[NMAX + 2];
bool firstTime;

void BucketSort()
{
	///sortare dupa rnk.second

	for(int i = 0; i <= N; i++)
		count[i] = 0;

	for(int i = 1; i <= N; i++)
		count[v[i].rnk.second]++;

	if(!firstTime)
		{
			firstTime = true;

			for(int i = 1; i < 256; i++)
				count[i] += count[i - 1];
		}
	else
		{
			for(int i = 1; i <= N; i++)
				count[i] += count[i - 1];
		}

	for(int i = N; i >= 1; i--)
		aux[count[v[i].rnk.second]--] = v[i];

	for(int i = 1; i <= N; i++)
		v[i] = aux[i];

	///sortare dupa rnk.first si rnk.second
	
	for(int i = 0; i <= N; i++)
		count[i] = 0;

	for(int i = 1; i <= N; i++)
		count[v[i].rnk.first]++;

	for(int i = 1; i <= N; i++)
		count[i] += count[i - 1];

	for(int i = N; i >= 1; i--)
		aux[count[v[i].rnk.first]--] = v[i];

	for(int i = 1; i <= N; i++)
		v[i] = aux[i];

	///reetichetare

	int k = 0;
	newRank[1] = ++k;

	for(int i = 2; i <= N; i++)
		if((v[i].rnk.first > v[i - 1].rnk.first) || (v[i].rnk.first == v[i - 1].rnk.first && v[i].rnk.second > v[i - 1].rnk.second))
			newRank[i] = ++k;
		else
			newRank[i] = k;

	for(int i = 1; i <= N; i++)
		v[i].rnk.first = newRank[i];

	for(int i = 1; i <= N; i++)
		posv[v[i].startingPos] = i;
}

void BuildSuffixArray()
{
	for(int i = 1; i <= N; i++)
	{
		v[i].startingPos = i;
		v[i].rnk.first = 0;
		v[i].rnk.second = s[i] - '0';
	}

	BucketSort();

	for(int l = 2; l < 2 * N; l *= 2)
	{
		for(int i = 1; i <= N; i++)
			if(v[i].startingPos + l / 2 <= N)
				v[i].rnk.second = v[posv[v[i].startingPos + l / 2]].rnk.first;
			else
				v[i].rnk.second = 0;

		BucketSort();
	}

}

int lcp[NMAX + 2];

void ComputeLCP()
{
	int current = 0;

	for(int i = 1; i <= N; i++)
	{
		int x = posv[i], posX = i, posY = v[x + 1].startingPos;

		while(posX + current <= N && posY + current <= N && s[posX + current] == s[posY + current])
			current++;

		lcp[x] = current;
		current = max(0, current - 1);
	}
}

const int LOGMAX = 14;
vector <int> rmq[LOGMAX + 1];
int lg2[NMAX + 2];

void BuildRmq()
{
	for(int i = 2; i <= N; i++)
		lg2[i] = lg2[i / 2] + 1;

	for(int i = 1; i <= N; i++)
		rmq[0].push_back(lcp[i]);

	for(int i = 1; i <= LOGMAX; i++)
		if((1 << i) > rmq[0].size()) break;
		else
		{
			for(int j = 0; j < rmq[0].size(); j++)
				if((1 << i) + j > rmq[0].size()) break;
				else rmq[i].push_back(min(rmq[i - 1][j], rmq[i - 1][j + (1 << (i - 1))]));
		}
}

int QueryRmq(int l, int r)
{
	l--, r--;

	int k = lg2[r - l + 1];

	return min(rmq[k][l], rmq[k][r - (1 << k) + 1]);
}

bool isOk(int l)
{
	for(int i = 1; i <= N - K + 1; i++)
		if(QueryRmq(i, i + K - 1) >= l)
			return true;

	return false;
}

int main()
{
	cin >> N >> K;
	cin >> (s + 1);

	if(K == 1)
		{	
			cout << N << '\n';
			return 0;
		}

	BuildSuffixArray();

	ComputeLCP();

	BuildRmq();

	/*
	for(int i = 1; i <= N; i++)
	{
		cout << lcp[i] << ' ';
		for(int j = v[i].startingPos; j <= N; j++)
			cout << s[j];
		cout << '\n';
	}
	*/

	K--;

	int st = 1, dr = N, sol = 0;

	while(st <= dr)
	{
		int mid = (st + dr) >> 1;

		if(isOk(mid))
		{
			sol = mid;
			st = mid + 1;
		}
		else
			dr = mid - 1;
	}

	cout << sol << '\n';

	return 0;
}