Cod sursa(job #882656)

Utilizator vendettaSalajan Razvan vendetta Data 19 februarie 2013 11:58:10
Problema Substr Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.24 kb
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>

using namespace std;

ifstream f("substr.in");
ofstream g("substr.out");

#define nmax 16400
#define Logmax 15

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 suffixArray(){
    int sz = S.size();
    for(int i=0; i<S.size(); ++i){
        Poz[0][i+1] = cod(i);
    }

    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];
        }
        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
    }
    for(int i=1; i<=sz; ++i){
        cout << Rez[i] << "\n";
        for(int j=Rez[i]; j<=S.size(); ++j){
            g << S[j-1];
        }
        g << "\n";
    }
}

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){
            if (sz1 > sz2) ok = 1;
            else ok = -1;
        }
        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; }
        }
        int sz1 = S.size() - Rez[mij] + 1;// lungimea secventei Rez[mij]..S.size();
        int sz2 = y -x + 1;// lungimea secventei fixate
        if (ok == 0){
            if ( sz1 > sz2 ) ok = 1;
            else ok = -1;
        }
        if (ok == 1){
            dr = mij;
        }else st = mij;
    }
    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){
            st = mij;
        }else dr = mij;
    }
    return st;
}

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 << Max << "\n";
}

int main(){
    citeste();
    rezolva();

    return 0;
}