Cod sursa(job #1856766)

Utilizator BrandonChris Luntraru Brandon Data 25 ianuarie 2017 13:38:19
Problema Substr Scor 30
Compilator cpp Status done
Runda Arhiva de probleme Marime 2.88 kb
#include <fstream>
#include <cmath>
#include <algorithm>
#include <cstring>

using namespace std;

ifstream cin ("substr.in");
ofstream cout ("substr.out");

const int MaxN = 16500, MaxLog = 15, HashMod1 = 666013, HashMod2 = 733333, HashBase = 73;

string str;
int n, k, globalAns;
int suffixArray[MaxLog][MaxN], Log[MaxN], H1[HashMod1 + 5], H2[HashMod2 + 5];

class StrSeg {
public:
  int lfCode, rgCode, pos;

  inline bool operator < (const StrSeg &other) const {
    if (lfCode == other.lfCode) {
      return rgCode < other.rgCode;
    }

    return lfCode < other.lfCode;
  }
};

StrSeg segOf[MaxN];

void InitSuffixArray() {
  for (int i = 0; i < n; ++i) {
    suffixArray[0][i] = str[i] + 1;
  }

  for (int step = 1; step <= Log[n]; ++step) {
    int prevLng = (1 << (step - 1));
    for (int i = 0; i < n; ++i) {
      segOf[i].lfCode = suffixArray[step - 1][i];
      segOf[i].rgCode = (i + prevLng < n) ? suffixArray[step - 1][i + prevLng] : 0;
      segOf[i].pos = i;
    }

    stable_sort(&segOf[0], &segOf[n]);
    int segTop = 0;
    suffixArray[step][segOf[0].pos] = ++segTop;
    for (int i = 1; i < n; ++i) {
      if (segOf[i].lfCode != segOf[i - 1].lfCode or segOf[i].rgCode != segOf[i - 1].rgCode) {
        ++segTop;
      }

      suffixArray[step][segOf[i].pos] = segTop;
    }
  }
}

void LCP(int index1, int index2, int length) {
  int pos1 = segOf[index1].pos;
  int pos2 = segOf[index2].pos;
  int Hash1 = 0;
  int Hash2 = 0;
  int lngLCP = 0;
  for (int step = Log[length]; step >= 0; --step) {
    int currLng = (1 << step);
    if (suffixArray[step][pos1] and lngLCP + currLng <= length and suffixArray[step][pos1] == suffixArray[step][pos2]) {
      Hash1 = ((1LL * Hash1 * HashBase) + suffixArray[step][pos1]) % HashMod1;
      Hash2 = ((1LL * Hash2 * HashBase) + suffixArray[step][pos2]) % HashMod2;

      pos1 += currLng;
      pos2 += currLng;
      lngLCP += currLng;
    }
  }

  if (lngLCP == length) {
    H1[Hash1] += 1 + (H1[Hash1] == 0);
    H2[Hash2] += 1 + (H2[Hash2] == 0);
  }
}

bool Check(int length) {
  memset(H1, 0, sizeof H1);
  memset(H2, 0, sizeof H2);
  for (int i = 1; i < n; ++i) {
    LCP(i, i - 1, length);
  }

  bool ok1 = false;
  bool ok2 = false;
  for (int i = 0; i < HashMod2; ++i) {
    if (H2[i] >= k) {
      ok2 = true;
    }

    if (i < HashMod1 and H1[i] >= k) {
      ok1 = true;
    }
  }

  return ok1 and ok2;
}

int BinSearch(int lf = 1, int rg = n) {
  int ans = 0;
  while (lf <= rg) {
    int med = (lf + rg) / 2;
    if (Check(med)) {
      lf = med + 1;
      ans = med;
    }
    else {
      rg = med - 1;
    }
  }

  return ans;
}

int main() {
  cin >> n >> k >> str;
  for (int i = 2; i < MaxN; ++i) {
    Log[i] = Log[i / 2] + 1;
  }

  InitSuffixArray();
  globalAns = BinSearch();
  cout << globalAns << '\n';
  return 0;
}