Cod sursa(job #882989)

Utilizator vendettaSalajan Razvan vendetta Data 19 februarie 2013 17:14:19
Problema Substr Scor 90
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.49 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

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

#define nmax (1<<14)+4
#define Logmax 16
#define ll long long

int n, K, Poz[Logmax][nmax];
typedef struct {
    int a, b, poz;
}camp;
camp L[nmax];
int Rez[nmax], Prefix[nmax];
deque<int> dq;
//string S;
char S[nmax];

void citeste(){
    f >> n >> K;
    //f.get(); getline(f, S);
    f.getline(S, nmax);
    f.getline(S, nmax);
}

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

    int lim = 1; // primul 2^lim >= n;
    for(; 1<<lim < n; ++lim); // acum 1<<lim >= n;
    for(int k=1; k<=lim; ++k){
        for(int i=1; i<=n; ++i){
            L[i].a = Poz[k-1][i];
            int newI = i + (1<<(k-1));
            if (newI > n) L[i].b = -1000;
                else L[i].b = Poz[k-1][newI];
            L[i].poz = i;
        }
        sort( L+1, L+n+1, cmp );
        Poz[ k ][ L[1].poz ] = 1;
        for(int i=2; i<=n; ++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<=n; ++i){
        Rez[ Poz[lim][i] ] = i;// al poz[lim][i] -lea sufix in ordine crescatoare e al i-lea sufix din sirul initial
    }
}

inline int Cmlpc(int x){
    int i = Rez[x]; int j = Rez[x-1];
    //if (i == j) return n - j + 1;
    //fac o cautare binara pe biti; adica imi construiesc rezultatul bit cu bit
    int rez = 0;
    for(int k=Logmax-1; k>=0 && i<=n && j<=n; --k){
        if ( Poz[k][i] == Poz[k][j] && (i + (1<<k) <= n ) && (j + (1<<k) <= n) ){//daca prefixul de lungime 2^k e la fel ma duc mai daparte
            rez += (1<<k); i += (1<<k); j += (1<<k);
        }
    }
    return rez;
}

void bagaPrefixe(){
    for(int i=2; i<=n; ++i){
        // cel mai lung prefix dintre cuvintele Rez[i]...n; Rez[i-1]...n;
        Prefix[i] = Cmlpc(i);
    }
}

void rezolva(){
    // dupace ce am sortate sufixele pentru feicare secventa de K sufixe vad care e cel mai lung prefix a acestor sufixe
    // bag un suffix array iar apoi tin minte pentru fiecare sufix cel mai lung prefix dintre el si sufixul i-1;
    // astfel pentru o secvnte de sufix [x,..y] fixata cel mai lung prefix va fi minimul de pe intervalul [x+1, ..y] =>
    // raspunsul va fi maximul acestor minime
    suffixArray();
    bagaPrefixe();
    // si acum bag pt fiecare secventa de k
    for(int i=2; i<=K; ++i){
        while( dq.size() && Prefix[dq.back()] >= Prefix[i]) dq.pop_back();
        while( dq.size() && dq.front() + K -1 <= i) dq.pop_front();
        dq.push_back( i );
    }
    int Max = Prefix[ dq.front() ];
    for(int i=K+1; i<=n; ++i){
        while( dq.size() && Prefix[ dq.back() ] >= Prefix[i]) dq.pop_back();
        while( dq.size() && dq.front() + K -1 <= i ) dq.pop_front();
        dq.push_back(i);
        Max = max(Max, Prefix[ dq.front() ]);
    }
    cout << Max << "\n";
    g << Max << "\n";
}

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

    f.close();
    g.close();

    return 0;
}