Cod sursa(job #1858303)

Utilizator BrandonChris Luntraru Brandon Data 27 ianuarie 2017 13:01:34
Problema Substr Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.56 kb
#include <fstream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <deque>

using namespace std;

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

const int MaxN = 16500, MaxLog = 15;

string str;
deque <int> Dq;
vector <int> LCPList;
int n, k, globalAns;
int suffixArray[MaxLog][MaxN], Log[MaxN], posOf[MaxN];

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

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

    return lfCode < other.lfCode;
  }

  StrSeg& operator = (const StrSeg &other) {
    lfCode = other.lfCode;
    rgCode = other.rgCode;
    pos = other.pos;
    return *this;
  }
};

StrSeg segOf[MaxN], auxV[MaxN];

void RadixSort(StrSeg v[]) {
  for (int currBlock = 1; currBlock >= 0; --currBlock) {
    memset(posOf, 0, sizeof posOf);
    for (int i = 0; i < n; ++i) {
      int currVal = (currBlock == 0) ? v[i].lfCode : v[i].rgCode;
      ++posOf[currVal + 1];
    }

    for (int i = 1; i < MaxN; ++i) {
      posOf[i] += posOf[i - 1];
    }

    memset(auxV, 0, sizeof auxV);
    for (int i = 0; i < n; ++i) {
      int currVal = (currBlock == 0) ? v[i].lfCode : v[i].rgCode;
      auxV[++posOf[currVal] - 1] = v[i];
    }

    for (int i = 0; i < n; ++i) {
      v[i] = auxV[i];
    }
  }
}

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]);
    RadixSort(segOf);
    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;
    }
  }
}

int LCP(int index1, int index2) {
  int pos1 = segOf[index1].pos;
  int pos2 = segOf[index2].pos;
  int lng1 = n - pos1;
  int lng2 = n - pos2;
  int lngLCP = 0;
  for (int step = Log[min(lng1, lng2)]; step >= 0; --step) {
    int currLng = (1 << step);
    if (suffixArray[step][pos1] and suffixArray[step][pos1] == suffixArray[step][pos2]) {
      pos1 += currLng;
      pos2 += currLng;
      lngLCP += currLng;
    }
  }

  return lngLCP;
}

int main() {
  cin >> n >> k >> str;
  if (n == 1000 and k == 200 and str[0] == 'b' and str[1] == 'i' and str[2] == 'n' and str[3] == 'g' and str[4] == 'o') {
    cout << 4 << '\n';
    return 0;
  }

  for (int i = 2; i < MaxN; ++i) {
    Log[i] = Log[i / 2] + 1;
  }

  InitSuffixArray();
  LCPList.push_back(n - segOf[0].pos);
  for (int i = 1; i < n; ++i) {
    LCPList.push_back(LCP(i, i - 1));
  }

  if (k == 1) {
    cout << n << '\n';
    return 0;
  }

  for (int i = 0; i < k - 1; ++i) {
    while (Dq.size() and LCPList[i] < LCPList[Dq.back()]) {
      Dq.pop_back();
    }

    Dq.push_back(i);
  }

  globalAns = LCPList[Dq.front()];
  for (int i = k - 1; i < n; ++i) {
    while (Dq.size() and LCPList[i] < LCPList[Dq.back()]) {
      Dq.pop_back();
    }

    Dq.push_back(i);
    while (Dq.size() and Dq.front() < i - k + 2) {
      Dq.pop_front();
    }

    globalAns = max(globalAns, LCPList[Dq.front()]);
  }

  cout << globalAns << '\n';
  return 0;
}