Cod sursa(job #1765616)

Utilizator ReksioCroftOctavian Florin Staicu ReksioCroft Data 26 septembrie 2016 21:17:53
Problema Substr Scor 100
Compilator c Status done
Runda Arhiva de probleme Marime 4.31 kb
#include <stdio.h>
#define nmax 16384
#define baza 62         ///baza cu cifre, litere mari si litere mici
#define mod 702113
#define rabinmod1 191707
#define rabinmod2 120569

typedef struct{
    int rk1, rk2, next, frecv;
}nod;
nod v[nmax+1];

char s[16384];
int n, k, ok, max, poz;
int hash[mod];          ///capul listei
int cod[123];           ///convertim fiecafre caracter la baza 62
int convrabin1[nmax];   ///vector utilizat la operatii asupra nr in baza 62
int convrabin2[nmax];   ///(sterge prima cifra si adauga ulima cifra )

int MAX( int x, int y ){
    return x>y ? x:y;
}

void initbaza(){
    int i;
    ///numere care sunt multiplii bazei pt a sterge prima cifra
    convrabin1[0] = convrabin2[0] = 1;
    for( i=1; i<=n; i++ ){
        convrabin1[i] = ( convrabin1[i-1] * baza ) % rabinmod1;
        convrabin2[i] = ( convrabin2[i-1] * baza ) % rabinmod2;
    }
    ///conversia caracterelor la baza 62
    char c;
    for( c='0'; c<='9'; c++ )
        cod[c] = c - '0';
    for( c='A'; c<='Z'; c++ )
        cod[c] = c - 'A' + 10;
    for( c='a'; c<='z'; c++ )
        cod[c] = c - 'a' + 36;
}

void inithashtable(){   ///sterand vectorul hash se vor pierde informatiile listei
    int i;
    for( i=poz=0; i<mod; i++ )
        hash[i] = 0;
}

void caut( int rabinkarp1, int rabinkarp2 ){
    int pozhash, adauga=1;
    for( pozhash = hash[ rabinkarp1%mod ]; pozhash!=0 && adauga==1; pozhash = v[pozhash].next ){///caut elementul ce se incadreza cu cele 2 hash-uri
        if( rabinkarp1 == v[pozhash].rk1 && rabinkarp2 == v[pozhash].rk2 ){
            adauga = 0;
            max = MAX( max, ++v[pozhash].frecv ); /// incrementez nr aparitii si calculez noul maxim
            if( max == k )  ///daca am gasit o secventa cu lungimea minima k
                ok = 1;
        }
    }
    if( adauga==1 ){                              ///daca nu exista acest nr in lista
        v[++poz].rk1 = rabinkarp1;               ///hash nr 1
        v[poz].rk2 = rabinkarp2;                ///hash nr 2
        v[poz].next = hash[rabinkarp1%mod];    ///lista
        hash[ rabinkarp1%mod ] = poz;         ///capul listei
        v[poz].frecv = 1;
    }
}

int gasit( int lung ){
    int i, rabinkarp1, rabinkarp2;
    rabinkarp1 = rabinkarp2 = 0;
    max = 1;
    inithashtable();    ///reinitializam capul ce va determina reinitializarea listei
    ok = 0;          ///daca nu am gasit un subsir de acea dimensiune ce apare de minim k ori
    for( i=0; i<lung; i++ ){ ///determinam hash numarului de la inceput pana la nrcaractere-1 al subsirului actual
        rabinkarp1 = ( rabinkarp1 * baza + cod[ s[i] ] ) % rabinmod1;
        rabinkarp2 = ( rabinkarp2 * baza + cod[ s[i] ] ) % rabinmod2;
    }
    for( i=lung; i<n && ok==0; i++ ){
        rabinkarp1 = ( rabinkarp1 * baza + cod[ s[i] ] ) % rabinmod1;
        rabinkarp2 = ( rabinkarp2 * baza + cod[ s[i] ] ) % rabinmod2;

        caut( rabinkarp1, rabinkarp2 );      ///cautam daca apare acest nr in lista

        ///eliminam prima cifra
        rabinkarp1 = ( ( rabinkarp1 - convrabin1[ lung ] * cod[ s[ i-lung] ] ) % rabinmod1 + rabinmod1 ) % rabinmod1;
        rabinkarp2 = ( ( rabinkarp2 - convrabin2[ lung ] * cod[ s[ i-lung] ] ) % rabinmod2 + rabinmod2 ) % rabinmod2;
    }
    return( max>= k );
}

int sol( int start, int stop ){ ///realizam o cautare binare pt gasirea lungimii sirului
    int mij;
    while( stop-start>1 ){
        mij = ( start + stop ) >> 1;
        if( gasit(mij) == 1 )       ///daca am gasit un subsir ce apare de minim k ori, avansam cu inceputul
            start = mij;           ///ce va determina cresterea mojlocului, si implicit lungimea subsirului pt urmatoarea cautare
        else
            stop = mij;             ///daca nu l-am gasit, micsoram dimensiunea subsirului prin reducerea mijlocului
    }
    return stop;
}

int main()
{
    int i;
    FILE *fin, *fout;
    fin = fopen( "substr.in", "r" );
    fscanf( fin, "%d%d", &n, &k );
    fgetc( fin );       ///citim in gol caracterul '\n'
    for( i=0; i<n; i++ )
        s[i] = fgetc( fin );        ///citim sirul
    fclose( fin );
    fout = fopen( "substr.out", "w" );
    ///initializam vectori pt converisa mai usoara la baza 62
    initbaza();
    fprintf( fout, "%d\n", sol( 0, n ) );
    fclose( fout );
    return 0;
}