Cod sursa(job #2395152)

Utilizator stoianmihailStoian Mihail stoianmihail Data 2 aprilie 2019 11:52:00
Problema Potrivirea sirurilor Scor 24
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.05 kb
#include <fstream>
#include <iostream>
#include <vector>
#include <cstring>
#include <cassert>

using namespace std;

#define MAX_LEN 2000000

int size, remained;
char pattern[MAX_LEN + 2];
char text[MAX_LEN + 2];
int z[MAX_LEN + 1];

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

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

bool inverse(char a, char b) {
  return a > b;
}

bool normal(char a, char b) {
  return a < b;
}

int computeMaxSuffix(const char* pattern, int32_t length, int32_t& period, bool compare(char, char)) {
   int32_t maxSuffix = -1;
   int32_t ptr = 0, candPeriod = 1;
   period = 1;

   while (ptr + candPeriod < length) {
      char c1 = pattern[ptr + candPeriod];
      char c2 = pattern[maxSuffix + candPeriod];
      if (!compare(c1, c2)) {
         if (c1 == c2) {
            if (candPeriod == period) {
               candPeriod = 1;
               ptr += period;
            } else {
               candPeriod++;
            }
         } else {
            period = candPeriod = 1;
            maxSuffix = ptr;
            ptr++;
         }
      } else {
         ptr += candPeriod;
         period = ptr - maxSuffix;
         candPeriod = 1;
      }
   }
   return maxSuffix;
}

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;
    }
  }
}

void preparePattern(char* pattern, int length, int& maxSuffix, int& period) {
  int period1, period2;
  int maxSuffix1 = computeMaxSuffix(pattern, length, period1, normal);
  int maxSuffix2 = computeMaxSuffix(pattern, length, period2, inverse);

  if (maxSuffix1 > maxSuffix2) {
    maxSuffix = maxSuffix1;
    period = period1;
  } else {
    maxSuffix = maxSuffix2;
    period = period2;
  }
}

int choose(int val) {
  while (remained < size && z[remained] < val)
    remained++;
  if (remained < size) {
    //cerr << "voitai " << val << " ti-am dat " << z[remained] << endl;
    return z[remained];
  } else {
    return z[size - 1];
  }
}

vector<int> twoWaySearch(char* haystack, int haystacklen, char* needle, int needlelen) {
  int maxSuffix, period;
  preparePattern(needle, needlelen, maxSuffix, period);

  cerr << "prepare liefert " << maxSuffix << " " << period << endl;

  int sigma = 0;
  int theta = 1 + maxSuffix;
  int lastMatch = 0;
  vector<int> matches;

  remained = 0;

  while (sigma <= haystacklen - needlelen) {
    while (theta < sigma + needlelen && haystack[theta] == needle[theta - sigma]) {
      theta++;
    }
    if (theta < sigma + needlelen) {
      sigma = theta - maxSuffix;
      theta++;
      if (sigma < lastMatch) {
        assert(0);
        sigma = lastMatch - needlelen + choose(sigma - lastMatch + needlelen);
      }
      if (sigma + maxSuffix + 1 > theta)
        theta = sigma + maxSuffix + 1;
    } else {
      int alfa = MAX(sigma, lastMatch);
      int lim = alfa - sigma;
      int offset = maxSuffix;
      while (offset >= lim && haystack[sigma + offset] == needle[offset])
        --offset;
      if (offset < lim) {
        matches.push_back(sigma);
      }
      sigma += period;

      // reset lastMatch.
      remained = 0;
      lastMatch = theta;
      if (sigma + maxSuffix + 1 > theta)
        theta = sigma + maxSuffix + 1;
    }
  }
  return matches;
}

int main(void) {
  ifstream in("strmatch.in");
  ofstream out("strmatch.out");

  in >> pattern >> text;

  int M = strlen(pattern);
  int N = strlen(text);

  Z(pattern, M);

  for (int i = 1; i < M; i++) {
    if (z[i] + i == M) {
      z[size++] = i;
    }
  }
  z[size++] = M;

  cerr << "Periods\n";
  for (int i = 0; i < size; i++) {
    cerr << z[i] << " ";
  }

  vector<int> matches = twoWaySearch(text, N, pattern, M);
  out << matches.size() << endl;
  for (int i = 0; i < matches.size() && i < 1000; i++)
    out << matches[i] << " ";
  return 0;
}