Cod sursa(job #1558585)

Utilizator stoianmihailStoian Mihail stoianmihail Data 29 decembrie 2015 13:28:54
Problema Substr Scor 0
Compilator c Status done
Runda Arhiva de probleme Marime 3.04 kb
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define P 29850523
#define E 29850517
#define MOD 99991
#define Nadejde 16390
#define UTF8 256
#define BASE 67
#define SIGMA 26

typedef struct {
  int p, e, end, count, next;
} list;

int N, K, len;
int max, flag;
char s[Nadejde];     // sirul nostru.
int code[UTF8];      // codul hash al fiecarui caracter.
int buff, adj[MOD];  // capetele listelor din tabela.
list l[Nadejde + 1]; // tabela hash.
int pBases[Nadejde + 1], eBases[Nadejde + 1];

/** max(X, Y). **/
int MAX(int X, int Y) {
  return X > Y ? X : Y;
}

/** Precalculeaza bazele si sirul "code". **/
void getBases() {
  int i;

  pBases[0] = eBases[0] = 1;
  for (i = 1; i <= N; i++) {
    pBases[i] = (pBases[i - 1] * BASE) % P;
    eBases[i] = (eBases[i - 1] * BASE) % E;
  }

  char c;
  for (c = 'a'; c <= 'z'; c++) {
    code[c] = c - 'a' + 1;
  }
  for (c = 'A'; c <= 'Z'; c++) {
    code[c] = c - 'A' + SIGMA + 1;
  }
  for (c = '0'; c <= '9'; c++) {
    code[c] = c - '0' + (SIGMA << 1) + 2;
  }
}

/** Initializeaza tabela hash. **/
void init() {
  int i;
  for (i = buff = 0; i < MOD; i++) {
    adj[i] = 0;
  }
}

/** Adauga in tabela hash perechea (p, e, i). **/
void add(int h, int p, int e, int i) {
  l[++buff].p = p;
  l[buff].e = e;
  l[buff].end = i;
  l[buff].count = 1;
  l[buff].next = adj[h];
  adj[h] = buff;
}

int equal(int i, int j) {
  int k;
  for (k = 0; (k < len) && (s[i - k] == s[j - k]); k++);
  return k == len;
}

/** Cauta perechea (p, e, i) in tabela. **/
void find(int p, int e, int i) {
  int pos, same = 0, h = p % MOD;

  for (pos = adj[h]; (pos != 0) && (!same); pos = l[pos].next) {
    if ((l[pos].p == p) && (l[pos].e == e)) {
      same = 1;
      max = MAX(max, ++l[pos].count);

      if (max == K) {
        flag = 1;
      }
    }
  }

  /* Daca nu am gasit-o, o punem in tabela. */
  if (!same) {
    add(h, p, e, i);
  }
}

/** Vezi daca sunt mai mult de K aparitii de lungime "len". **/
int try() {
  int i, lim = len - 1, pHash = 0, eHash = 0;

  init();

  max = 1;
  for (i = flag = 0; i < lim; i++) {
    pHash = (pHash * BASE + code[s[i]]) % P;
    eHash = (eHash * BASE + code[s[i]]) % E;
  }
  for (i = lim; (i < N) && (!flag); i++) {
    pHash = (pHash * BASE + code[s[i]]) % P;
    eHash = (eHash * BASE + code[s[i]]) % E;

    find(pHash, eHash, i);

    pHash = ((pHash - pBases[lim] * code[s[i - lim]]) % P + P) % P;
    eHash = ((eHash - eBases[lim] * code[s[i - lim]]) % E + E) % E;
  }
  return (max >= K);
}

/** Cauta binar rezultatul. **/
int bSearch(int lo, int hi) {
  while (hi - lo > 1) {
    len = (lo + hi) >> 1;
    printf("%d\n", len);
    if (try()) {
      lo = len;
    } else {
      hi = len;
    }
  }
  return lo;
}

int main(void) {
  FILE *f = fopen("substr.in", "r");

  /* Citirea datelor. */
  fscanf(f, "%d %d\n%s", &N, &K, s);
  fclose(f);

  /* Precalcularea bazelor. */
  getBases();

  /* Calcularea solutiei si afisarea ei. */
  freopen("substr.out", "w", stdout);
  fprintf(stdout, "%d\n", bSearch(0, N + 1));
  fclose(stdout);

  /// Multumim Doamne!
  puts("Doamne ajuta!");
  return 0;
}