Pagini recente » Cod sursa (job #2221672) | Cod sursa (job #3157366) | Cod sursa (job #236670) | Cod sursa (job #1472003) | Cod sursa (job #882843)
Cod sursa(job #882843)
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
using namespace std;
ifstream f("substr.in");
ofstream g("substr.out");
#define nmax 16400
#define Logmax 16
string S;
int n, K;
int Poz[Logmax][nmax];
typedef struct{
int a, b, poz;
}camp;
camp L[nmax];
int Rez[nmax];
void citeste(){
f >> n >> K; f.get();
getline(f, S);
}
inline int cod(int x){
if (S[x] >= 'a' && S[x] <= 'z') return S[x] - 'a';
if (S[x] >= 'A' && S[x] <= 'Z') return S[x] - 'A' - 'a';
if (S[x] >= '0' && S[x] <= '9') return S[x] - '0' - 'a' - 'A';
}
bool cmp( camp A, camp B){
if (A.a == B.a) return A.b < B.b;
return A.a < B.a;
}
void afis(){
for(int i=1; i<=n; ++i){
for(int j=Rez[i]; j<=n; ++j) g << S[j-1];
g << "\n";
}
}
void suffixArray(){
int sz = S.size();
for(int i=0; i<S.size(); ++i){
Poz[0][i+1] = cod(i);
//cout << cod(i)<<"\n";
}
int lim = 1; // primul 2^lim >= sz;
for(; 1<<lim < sz; ++lim);
// acum 1<<lim >= sz;
for(int k=1; k<=lim; ++k){
for(int i=1; i<=sz; ++i){
L[i].a = Poz[k-1][i];
int newI = i + (1<<(k-1));
if (newI > sz) L[i].b = -1000;
else L[i].b = Poz[k-1][newI];
L[i].poz = i;
}
sort( L+1, L+sz+1, cmp );
Poz[ k ][ L[1].poz ] = 1;
for(int i=2; i<=sz; ++i){
if ( L[i].a == L[i-1].a && L[i].b == L[i-1].b)
Poz[k][ L[i].poz ] = Poz[k][ L[i-1].poz ];
else Poz[k][ L[i].poz ] = i;
}
}
for(int i=1; i<=sz; ++i){
Rez[ Poz[lim][i] ] = i;// al poz[lim][i] -lea sufix in ordine crescatoare e al i-lea sufix din sirul initial
}
//afis();
}
inline int cbSt(int x, int y){
// ultimul mai mic ca si mine
int st = 0; int dr = n+1;
while(dr - st > 1){
int mij = (st + dr) / 2;
int ok = 0; // sunt la fel
// ok = 1; insemana ca mij=ul e < ca si mine
// ok = -1; insmena ca mij-ul > ca si mine
for(int i=Rez[mij], j=x; j<=y && i<=S.size(); ++j, ++i){// j-ul e indexat corect; i-ul e indexat de la 1
if (S[i-1] == S[j]) continue;
if (S[i-1] < S[j]){ ok = 1; break;}
if (S[i-1] > S[j]){ ok = -1; break;}
}
int sz1 = S.size() - Rez[mij] + 1;// lungimea secventei Rez[mij]..S.size();
int sz2 = y -x + 1;// lungimea secventei fixate
if (ok == 0){//daca sunt la fel
if (sz1 < sz2 ) ok = 1;// sufixul e mai mic ca si mine daca are lungimea mai mica ca si mine
else ok = -1;// altfel e mai mare sau egal
}
if (ok == 1){
st = mij;
}else dr = mij;
}
return st;
}
inline int cbDr(int x, int y){
int st = 0; int dr = n+1;
while(dr - st > 1){
int mij = (st + dr) / 2;
int ok = 0;
for(int i=Rez[mij], j=x; j<=y && i<=S.size(); ++j, ++i){
if (S[i-1] == S[j]) continue;
if (S[i-1] > S[j]){ ok =1; break;}
if (S[i-1] < S[j]){ ok = -1; break; }
}
if (ok == 1){// e bun; mij-ul e mai mare ca si mine desi incerc mai la stanga
dr = mij;
}else st = mij;// e mai mic sau e la fel deci incerc mai la dreapta
}
return dr;
}
inline int apare(int x, int y){
// deci am secventa x..y vreau sa vad de cat ori apare
return ( cbDr(x, y) - cbSt(x, y) + 1 - 2 );
}
inline int cauta(int poz){
// caut cea mai mare secventa din secventa poz...n care apare de cel putin K ori
// la sfarsit va fi evident de genul poz..ceva
--poz;// e indexat de la 1 iar sirul de la 0
int st = poz-1; int dr = S.size();
while( dr - st > 1){
int mij = ( st + dr ) / 2;
//secventa poz...mij
if ( apare(poz, mij) >= K){
//cout << poz << " " << mij << "\n";
st = mij;
}else dr = mij;
}
//return st;
return st - poz + 1;
}
void rezolva(){
// sortez sufixele iar apoi caut pentru fiecare sufix cea mai mare lungime care apare de cel putin K ori
suffixArray();
int Max = 0;
for(int i=1; i<=n; ++i){
Max = max(Max, cauta(i) );
}
//cout << apare(2, 3) << "\n";
g << Max << "\n";
}
int main(){
citeste();
rezolva();
return 0;
}