Cod sursa(job #1765477)

Utilizator ReksioCroftOctavian Florin Staicu ReksioCroft Data 26 septembrie 2016 19:35:07
Problema Substr Scor 20
Compilator c Status done
Runda Arhiva de probleme Marime 3.93 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
#define MAX(a, b) ( a>b ? a:b )
typedef struct{
    int rk1, rk2, next, frecv;
}nod;
nod v[nmax];

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


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
    for( i='0'; i<='9'; i++ )
        cod[i] = i - '0';
    for( i='A'; i<='Z'; i++ )
        cod[i] = i - 'A' + 10;
    for( i='a'; i<='z'; i++ )
        cod[i] = i - 'a' + 36;
}

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

void caut( int rabinkarp1, int rabinkarp2 ){
    int pozhash;
    pozhash = hash[ rabinkarp1%mod ];
    for( pozhash = hash[ rabinkarp1%mod ]; pozhash!=0 && ok==0; pozhash = v[pozhash].next ){
        if( rabinkarp1 == v[pozhash].rk1 && rabinkarp2 == v[pozhash].rk2 ){
            if( v[poz].frecv!=0 ){
                max = MAX( max, ++v[poz].frecv );
            }
            else{
                v[++poz].rk1 = rabinkarp1;
                v[poz].rk2 = rabinkarp2;
                v[poz].next = hash[rabinkarp1%mod];
                hash[ rabinkarp1%mod ] = poz;
                v[poz].frecv = 1;
            }
            if( max == k )
                ok = 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[i] ) % rabinmod1;
        rabinkarp2 = ( rabinkarp2 * baza + cod[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+1;
}

int main()
{
    int i;
    FILE *fin, *fout;
    fin = fopen( "substr.in", "r" );
    fscanf( fin, "%d%d\n", &n, &k );
    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-1 ) );
    fclose( fout );
    return 0;
}