Cod sursa(job #2413412)

Utilizator stoianmihailStoian Mihail stoianmihail Data 23 aprilie 2019 13:14:23
Problema Aho-Corasick Scor 25
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.13 kb
#include <fstream>

#include <vector>

#include <cmath>

#include <cassert>

#include <iostream>



using namespace std;



#define MAX_LEN 1000000



typedef vector<int> VI;

const double PI = acos(0) * 2;

unsigned partialSums[MAX_LEN + 1];



class complex

{

public:

	double a, b;

	complex() {a = 0.0; b = 0.0;}

	complex(double na, double nb) {a = na; b = nb;}

	const complex operator+(const complex &c) const

		{return complex(a + c.a, b + c.b);}

	const complex operator-(const complex &c) const

		{return complex(a - c.a, b - c.b);}

	const complex operator*(const complex &c) const

		{return complex(a*c.a - b*c.b, a*c.b + b*c.a);}

	double magnitude() {return sqrt(a*a+b*b);}

	void print() {printf("(%.3f %.3f)\n", a, b);}

};



class FFT

{

public:

	vector<complex> data;

	vector<complex> roots;

	VI rev;

	int s, n;



	void setSize(int ns)

	{

		s = ns;

		n = (1 << s);

		int i, j;

		rev = VI(n);

		data = vector<complex> (n);

		roots = vector<complex> (n+1);

		for (i = 0; i < n; i++)

			for (j = 0; j < s; j++)

				if ((i & (1 << j)) != 0)

					rev[i] += (1 << (s-j-1));

		roots[0] = complex(1, 0);

		complex mult = complex(cos(2*PI/n), sin(2*PI/n));

		for (i = 1; i <= n; i++)

			roots[i] = roots[i-1] * mult;

	}



	void bitReverse(vector<complex> &array)

	{

		vector<complex> temp(n);

		int i;

		for (i = 0; i < n; i++)

			temp[i] = array[rev[i]];

		for (i = 0; i < n; i++)

			array[i] = temp[i];

	}



	void transform(bool inverse = false)

	{

		bitReverse(data);

		int i, j, k;

		for (i = 1; i <= s; i++) {

			int m = (1 << i), md2 = m / 2;

			int start = 0, increment = (1 << (s-i));

			if (inverse) {

				start = n;

				increment *= -1;

			}

			complex t, u;

			for (k = 0; k < n; k += m) {

				int index = start;

				for (j = k; j < md2+k; j++) {

					t = roots[index] * data[j+md2];

					index += increment;

					data[j+md2] = data[j] - t;

					data[j] = data[j] + t;

				}

			}

		}

		if (inverse)

			for (i = 0; i < n; i++) {

				data[i].a /= n;

				data[i].b /= n;

			}

	}



	static VI convolution(VI &a, VI &b)

	{

		int alen = a.size(), blen = b.size();

		int resn = alen; // size of the resulting array

		int s = 0, i;

		while ((1 << s) < resn) s++;	// n = 2^s

		int n = 1 << s;	// round up the the nearest power of two



		FFT pga, pgb;

		pga.setSize(s);	// fill and transform first array

		for (i = 0; i < alen; i++) pga.data[i] = complex(a[i], 0);

		for (i = alen; i < n; i++)	pga.data[i] = complex(0, 0);

		pga.transform();



		pgb.setSize(s);	// fill and transform second array

		for (i = 0; i < blen; i++)	pgb.data[i] = complex(b[i], 0);

		for (i = blen; i < n; i++)	pgb.data[i] = complex(0, 0);

		pgb.transform();



		for (i = 0; i < n; i++)	pga.data[i] = pga.data[i] * pgb.data[i];

		pga.transform(true);	// inverse transform

		VI result = VI (resn);	// round to nearest integer

		for (i = 0; i < resn; i++)	result[i] = (int) (pga.data[i].a + 0.5);



		int actualSize = resn - 1;	// find proper size of array

		while (result[actualSize] == 0)

			actualSize--;

		if (actualSize < 0) actualSize = 0;

		result.resize(actualSize+1);

		return result;

	}

};



unsigned square(uint32_t x) {

  return x * x;

}



int getSum(int pos, uint32_t needlelen) {

  return partialSums[pos + needlelen - 1] - ((!pos) ? 0 : partialSums[pos - 1]);

}



const int SIGMA = 26;

const int ALL = 1 << 8;

int alphaTable[ALL + 1];



void init() {

  for (char c = 'a'; c <= 'z'; c++)

    alphaTable[c] = c - 'a';

  for (char c = 'A'; c <= 'Z'; c++)

    alphaTable[c] = c - 'A' + SIGMA;

}



inline int encode(char c) {

  return alphaTable[c];

}



unsigned solve(VI& s, uint32_t size, string& pattern) {

  unsigned needlelen = pattern.size();

  if (needlelen > s.size())

    return 'N';

  VI p(needlelen);

  for (unsigned index = 0; index < needlelen; index++)

    p[needlelen - index - 1] = encode(pattern[index]);

  int constPattern = 0;

  for (unsigned index = 0; index < needlelen; index++)

    constPattern += square(p[index]);



  // Apply only for s and p.

  VI ret = FFT::convolution(s, p);



  // Shift the window at every step.

  unsigned noMatches = 0;

  for (unsigned i = 0; i < size - needlelen + 1; i++)

    noMatches += ((ret[i + needlelen - 1] << 1) == constPattern + getSum(i, needlelen));

  return noMatches;

}
int main(void) {

  ifstream cin("ahocorasick.in");

  ofstream cout("ahocorasick.out");



  init();



  string text;



  int Q;

  cin >> text >> Q;

  unsigned size = text.size();

  VI s(size);

  for (unsigned index = 0; index < size; index++) {

    s[index] = encode(text[index]);

    partialSums[index] = square(s[index]) + ((!index) ? 0 : partialSums[index - 1]);

  }

  while (Q--) {

    string pattern;

    cin >> pattern;

    cout << solve(s, size, pattern) << '\n';

  }

  return 0;

}