Cod sursa(job #2845369)

Utilizator NeacsuMihaiNeacsu Mihai NeacsuMihai Data 7 februarie 2022 19:09:22
Problema Substr Scor 90
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4 kb
#include <bits/stdc++.h>

#define SIGMA 1000
#define NMAX 16384 //saispemii treisute optzeci si patru

using namespace std;

ifstream fin ("substr.in");
ofstream fout ("substr.out");

int RASPUNS_FINAL;
int N, K;
int fr[SIGMA + 1];
int nr[SIGMA + 1];
char s[NMAX + 1];
int lg2[NMAX + 1];
int v[NMAX + 1];
int sA[14 + 1 + 1][NMAX];
pair< pair<int, int>, int > key[NMAX];

void build_lg2(int lim){
    lg2[1] = 0;
    for(int i = 2; i <= lim; i++){
        lg2[i] = lg2[i / 2] + 1;
    }
}

int LCP(int i, int j){
    int lg = 0;
    for(int k = lg2[N]; k >= 0 && i < N && j < N; k--){
        if( i + (1 << k) - 1 < N && sA[k][i] == sA[k][j] ){
            lg += (1 << k);
            i += (1 << k);
            j += (1 << k);
        }
    }

    return lg;
}

void build_suffixArray(){
    for(int i = 0; i < N; i++){
        fr[ s[i] ]++;
    }

    int dif = 0;
    for(int j = 0; j <= SIGMA; j++){
        if(fr[j] != 0){
            dif++;
            nr[j] = dif;
        }
    }

    for(int i = 0; i < N; i++){
        sA[0][i] = nr[ s[i] ];
    }

    for(int i = 1; i <= lg2[N] + 1; i++){
        for(int j = 0; j < N; j++){
            if( j + (1 << (i - 1) ) < N ){
                key[j] = { {sA[i - 1][j], sA[i - 1][j + (1 << (i - 1))]}, j };
            }
            else {
                key[j] = { {sA[i - 1][j], 0}, j };
            }
        }

        sort(key, key + N);

        int dist = 0;
        for(int j = 0; j < N; j++){
            if(j == 0 || key[j].first != key[j - 1].first){
                dist++;
            }

            sA[i][ key[j].second ] = dist;
        }
    }


    for(int j = 0; j < N; j++){
        v[ sA[ lg2[N] + 1 ][j] - 1 ] = j;
    }
}

void Read(){
    fin >> N >> K; fin.get();

    fin.getline(s, NMAX + 1);
}

int cautareBinaraStanga(int lo, int hi, int pivot){
    lo--;
    hi++;
    int rsp = -1;

    while(hi - lo > 1){
        int mid = lo + (hi - lo) / 2;

        if( LCP(v[mid], v[pivot]) == 0){
            lo = mid;
        }
        else {
            rsp = mid;
            hi = mid;
        }
    }

    return rsp;
}

int cautareBinaraDreapta(int lo, int hi, int pivot){
    lo--;
    hi++;
    int rsp = -1;

    while(hi - lo > 1){
        int mid = lo + (hi - lo) / 2;

        if( LCP(v[mid], v[pivot]) == 0){
            hi = mid;
        }
        else {
            rsp = mid;
            lo = mid;
        }
    }

    return rsp;
}

void Solve(){
    int L = -1, R = -1;
    for(int p = 0; p < N; p++){
        /*if(p <= R){
            nu face nimic
        }*/
        if(p > R) {
            L = p;
            R = cautareBinaraDreapta(p, N - 1, p);

            if(R - L + 1 >= K){
                /*
                    Acum incerc sa gasesc raspunsul meu aici
                */

                for(int i = L; i + K - 1 <= R; i++){
                    int j = i + K - 1;

                    int candidat = LCP(v[i], v[j]);

                    if(candidat > RASPUNS_FINAL){
                        RASPUNS_FINAL = candidat;
                    }
                }
            }
        }
    }

    /*
    for(int P = 0; P < N; P++){
        int st = cautareBinaraStanga( 0, P, P ); //sigur da diferit de -1
        int dr = cautareBinaraDreapta( P, N - 1, P ); //sigur da diferit de -1

        if(dr - st + 1 >= K){
            //atunci este candidat pentru maxim

            //fac gen moving window de dimensiune K
            for(int i = st; i <= dr - K + 1; i++){
                int j = i + K - 1;

                int candidat = LCP(v[i], v[j]);

                if(candidat > RASPUNS_FINAL){
                    RASPUNS_FINAL = candidat;
                }
            }
        }
    }
    */
}

int main()
{
    Read();
    if(K > N){
        fout << 0 << "\n";
        return 0;
    }

    build_lg2(N);
    build_suffixArray();
    Solve();

    fout << RASPUNS_FINAL << "\n";

    return 0;
}