Cod sursa(job #2391951)

Utilizator stoianmihailStoian Mihail stoianmihail Data 29 martie 2019 13:52:00
Problema Potrivirea sirurilor Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.43 kb
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
#include <cstring>

using namespace std;

#define MAX_LEN 4 * 500000
int size;
char pattern[MAX_LEN + 2];
char haystack[MAX_LEN + 2];
int z[MAX_LEN + 1];

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;

  z[0] = 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;
    }
  }
}

/* Computing of the maximal suffix for <= */
int maxSuf(char *x, int m, int *p) {
   int ms, j, k;
   char a, b;

   ms = -1;
   j = 0;
   k = *p = 1;
   while (j + k < m) {
      a = x[j + k];
      b = x[ms + k];
      if (a < b) {
         j += k;
         k = 1;
         *p = j - ms;
      }
      else
         if (a == b)
            if (k != *p)
               ++k;
            else {
               j += *p;
               k = 1;
            }
         else { /* a > b */
            ms = j;
            j = ms + 1;
            k = *p = 1;
         }
   }
   return ms;
}

/* Computing of the maximal suffix for >= */
int maxSufTilde(char *x, int m, int *p) {
   int ms, j, k;
   char a, b;

   ms = -1;
   j = 0;
   k = *p = 1;
   while (j + k < m) {
      a = x[j + k];
      b = x[ms + k];
      if (a > b) {
         j += k;
         k = 1;
         *p = j - ms;
      }
      else
         if (a == b)
            if (k != *p)
               ++k;
            else {
               j += *p;
               k = 1;
            }
         else { /* a < b */
            ms = j;
            j = ms + 1;
            k = *p = 1;
         }
   }
   return ms;
}

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

static vector<int> twoWaySearchImpl(char* haystack, int haystacklen, char* needle, int needlelen) {
  int i, j, maxSuffix, memory, p, period, q;
  //int matches = 0;
  int lastMatch = 0;

   /* Preprocessing */
   i = maxSuf(needle, needlelen, &p);
   /*j = maxSufTilde(needle, needlelen, &q);

   std::cerr << "1: " << p << " and " << i << endl;
   std::cerr << "2: " << q << " and " << j << endl;

   if (i > j) {
      maxSuffix = i;
      period = p;
   }
   else {
      maxSuffix = j;
      period = q;
   }
*/
  maxSuffix = i;
  period = p;

  vector<int> matches;

  Z(needle, needlelen);

  size = 1;
  for (int i = 1; i < needlelen; i++) {
    if (z[i] + i == needlelen) {
      z[size++] = i;
    }
  }
  z[size++] = needlelen;
/*
  std::cerr << "Z values\n";
  for (int i = 1; i < size; i++)
    std:: cerr << z[i] << " ";
  std:: cerr << "\n";
*/
  //std::cerr << "period von ihnen = " << period << endl;

  //assert(period == z[1]);

   /* Searching */
   /*if (memcmp(needle, needle + period, maxSuffix + 1) == 0) {
      j = 0;
      memory = -1;
      while (j <= haystacklen - needlelen) {
         i = MAX(maxSuffix, memory) + 1;
         while (i < needlelen && needle[i] == haystack[i + j])
            ++i;
         if (i >= needlelen) {
            i = maxSuffix;
            while (i > memory && needle[i] == haystack[i + j])
               --i;
            if (i <= memory)
              matches++;
            j += period;
            memory = needlelen - period - 1;
         }
         else {
            j += (i - maxSuffix);
            memory = -1;
         }
      }
   }
   else {*/
     //std::cerr << "enters here\n";
      //period = MAX(maxSuffix + 1, needlelen - maxSuffix - 1) + 1;
      j = 0;
      //std::cerr << "period danach " << period << " und maxSuffix = " << maxSuffix << endl;
      while (j <= haystacklen - needlelen) {
         i = maxSuffix + 1;
         while (i < needlelen && needle[i] == haystack[i + j])
            ++i;
         if (i >= needlelen) {
            //std::cerr << "partial match at " << (j + maxSuffix + 1) << endl;
            int lim = MAX(j, lastMatch) - j;
            i = maxSuffix;
            while (i >= lim && needle[i] == haystack[i + j])
               --i;
            //std::cerr << "lastMatch = " << lastMatch << " j = " << j << endl;
            //std::cerr << "lim = " << lim << " and stops at " << i << "\n";
            if (i < lim) {
              //std::cerr << "was";
              matches.push_back(j);
            }
            lastMatch = j + needlelen;
            j += period;
         }
         else {
            j += i - maxSuffix;
            if (j < lastMatch) {
              j = lastMatch - needlelen + choose(j - lastMatch + needlelen);
            }
         }
      }
   return matches;
}

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

  int N, Q;
  //cin >> N >> Q >> haystack;
  cin >> pattern >> haystack;
  vector<int> matches = twoWaySearchImpl(haystack, strlen(haystack), pattern, strlen(pattern));
  /*std::cerr << haystack << endl;
  while (Q--) {
    cin >> pattern;
    cout << twoWaySearchImpl(haystack, N, pattern, strlen(pattern)) << "\n";
  }*/
  cout << matches.size() << "\n";
  for (int i = 0; i < matches.size() && i < 1000; i++)
    cout << matches[i] << " ";
  cout << "\n";
  return 0;
}