Cod sursa(job #2389820)

Utilizator stoianmihailStoian Mihail stoianmihail Data 27 martie 2019 15:10:01
Problema Potrivirea sirurilor Scor 32
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.21 kb
#include <fstream>
#include <iostream>
#include <cstring>
#include <cassert>
#include <vector>

#define MAX_LEN 2000000

int N, M;
char pattern[MAX_LEN + 2];
char str[MAX_LEN + 2];
int z[MAX_LEN + 1];
int size;
std::vector<int> matches;

int MAX(int X, int Y) {
  return X > Y ? X : Y;
}

int MIN(int X, int Y) {
  return X < Y ? X : Y;
}

void Z(char *s, int len) {
  int i, l = 0, r = 0;

  for (i = 1; i < len; i++) {
    z[i] = (MIN(z[i - l], r - i + 1) & -(i <= r));
    while (s[z[i]] == s[z[i] + i]) {
      z[i]++;
    }
    if (i + z[i] - 1 > r) {
      r = i + z[i] - 1;
      l = i;
    }
  }
}

int computeMaxSuffix(char *needle, int len, int& period) {
   int maxSuffix, j, k;
   char a, b;

   maxSuffix = -1;
   j = 0;
   k = period = 1;
   while (j + k < len) {
      a = needle[j + k];
      b = needle[maxSuffix + k];
      if (a < b) {
         j += k;
         k = 1;
         period = j - maxSuffix;
      } else if (a == b) {
        if (k != period)
          ++k;
        else {
          j += period;
          k = 1;
        }
      } else {
        maxSuffix = j;
        j = maxSuffix + 1;
        k = period = 1;
      }
   }
   return maxSuffix;
}

int choose(int lim) {
  int i = 0;
  while (i < size && z[i] < lim) {
    i++;
  }
  if (i < size)
    return z[i];
  return z[size - 1];
}

int main(void) {
  std::fstream in("strmatch.in");
  in >> (pattern + 1) >> (str + 1);

  M = strlen(pattern + 1);
  N = strlen(str + 1);

  Z(pattern + 1, M);
  size = 0;
  for (int i = 1; i < M; i++) {
    if (z[i] + i == M) {
      z[size++] = i;
    }
  }
  if (!size || z[size - 1] != M)
    z[size++] = M;

  int period;
  int x = computeMaxSuffix(pattern + 1, M, period);

  //std::cout << "period = " << period << "\n";
  assert(period == z[0]);

  //std::cout << "x = " << x << "\n";

  int sigma = 1;
  int theta = 1 + x;
  int ro = 0;

  while (sigma <= N - M + 1) {
    //std::cout << "sigma = " << sigma << " and thteta = " << theta << "\n";
    while (theta < sigma + M && str[theta] == pattern[theta - sigma + 1]) {
      theta++;
    }
    //std::cout << "nach While " << theta << " und Grenze " << (sigma + M) << "\n";
    if (theta < sigma + M) {
      theta++;
      sigma = theta - x;
      if (sigma < ro) {
        //std::cout << "greater than " << (sigma - ro + M) << "so chosen " << choose(sigma - ro + M) << "\n";
        sigma = ro - M + choose(sigma - ro + M);
      }
      if (sigma + x > theta)
        theta = sigma + x;
    } else {
      //std::cout << "goes in\n";
      int alfa = MAX(sigma, ro);
      //std::cout << alfa << " mit " << sigma << " gegen " << (alfa - sigma + 1) << " mit length " << (sigma + x - alfa) << "\n";
      if (sigma + x - alfa < 0)
        matches.push_back(sigma);
      else if (memcmp(str + alfa, pattern + (alfa - sigma + 1), sigma + x - alfa) == 0)
        matches.push_back(sigma);
      sigma += period;
      ro = theta;
      if (sigma + x > theta)
        theta = sigma + x;
    }
  }

  std::ofstream out("strmatch.out");
  out << matches.size() << "\n";
  for (int i = 0; i < matches.size(); i++)
    out << (matches[i] - 1) << " ";
  return 0;
}