#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;

const double eps = 1e-12, pi = 3.14159265358979323846264;
const int maxn = 100086;
double answer = 1e10;
int n, len;

int sign(double u)
{
	if (fabs(u) < eps) return 0;
	if (u > 0) return 1;
	return -1;
}

struct Point
{
	double x, y;

	Point(double x1 = 0, double y1 = 0)
	{
		x = x1;
		y = y1;
	}

	friend Point operator + (Point a, Point b)
	{
		return Point(a.x + b.x, a.y + b.y);
	}

	friend Point operator - (Point a, Point b)
	{
		return Point(a.x - b.x, a.y - b.y);
	}

	friend Point operator * (Point a, double b)
	{
		return Point(a.x * b, a.y * b);
	}

	friend Point operator / (Point a, double b)
	{
		return Point(a.x / b, a.y / b);
	}

	friend bool operator == (Point a, Point b)
	{
		if (sign(a.x - b.x) != 0) return 0;
		if (sign(a.y - b.y) != 0) return 0;
		return 1;
	}

	double length()
	{
		return sqrt(x * x + y * y);
	}
}p[maxn], ans[maxn], P, now;

double det(Point a, Point b)
{
	return a.x * b.y - a.y * b.x;
}

double dot(Point a, Point b)
{
	return a.x * b.x + a.y * b.y;
}

double dist(Point a,Point b)
{
	Point c = a - b;
	return c.length();
}

bool cmp(Point a, Point b)
{
	if (sign(a.x - b.x) == 0)
		return (sign(a.y - b.y) < 0);
	return (sign(a.x - b.x) < 0);
}

void get_polygon()
{
	int tmp = 0, temp;
	sort(p + 1, p + 1 + n);
	for (int i = 1; i <= n; i++)
	{
		while((tmp >= 2) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	temp = tmp;
	for (int i = n - 1; i >= 1; i--)
	{
		while((tmp > temp) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	len = tmp - 1;
}

Point get_Cross(Point a, Point b, Point c, Point d)
{
	Point t1 = b - a, t2 = d - c;
	return c + d * det(c - a, t1) / det(t2, t1);
}

int main()
{
	double xmax = -1, ymax = -1;
	scanf("%d %lf %lf", &n, &P.x, &P.y);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf %lf", &p[i].x, &p[i].y);
		xmax = max(xmax, p[i].x);
		ymax = max(ymax, p[i].y);
	}
	p[++n] = Point(0, ymax);
	p[++n] = Point(xmax, 0);
	get_polygon();
	ans[len + 1] = ans[1];
	for (int i = 1; i <= len; i++)
		if (sign(det(ans[i], P)) >= 0 && sign(det(P, ans[i + 1])) >= 0)
		{
            //double r1 = det(P - ans[i], ans[i + 1] - ans[i]);
            //double r2 = det(ans[i + 1] - ans[i], Point(0, 0) - ans[i]);
			now = get_Cross(ans[i], ans[i + 1], Point(0, 0), P);
			printf("%.8lf\n", P.length() / now.length());
			//answer = min(answer, P.length() / now.length());
			//printf("%.8lf\n", r1 / r2 + 1);
			return 0;
		}
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;

const double eps = 1e-8, pi = 3.14159265358979323846264;
const int maxn = 100086;
double answer = 1e10;
int n, len;

int sign(double u)
{
	if (fabs(u) < eps) return 0;
	if (u > 0) return 1;
	return -1;
}

struct Point
{
	double x, y;

	Point(double x1 = 0, double y1 = 0)
	{
		x = x1;
		y = y1;
	}

	friend Point operator + (Point a, Point b)
	{
		return Point(a.x + b.x, a.y + b.y);
	}

	friend Point operator - (Point a, Point b)
	{
		return Point(a.x - b.x, a.y - b.y);
	}

	friend Point operator * (Point a, double b)
	{
		return Point(a.x * b, a.y * b);
	}

	friend Point operator / (Point a, double b)
	{
		return Point(a.x / b, a.y / b);
	}

	friend bool operator == (Point a, Point b)
	{
		if (sign(a.x - b.x) != 0) return 0;
		if (sign(a.y - b.y) != 0) return 0;
		return 1;
	}

	double length()
	{
		return sqrt(x * x + y * y);
	}
}p[maxn], ans[maxn], P, now;

double det(Point a, Point b)
{
	return a.x * b.y - a.y * b.x;
}

double dot(Point a, Point b)
{
	return a.x * b.x + a.y * b.y;
}

double dist(Point a,Point b)
{
	Point c = a - b;
	return c.length();
}

bool cmp(Point a, Point b)
{
	if (sign(a.x - b.x) == 0)
		return (sign(a.y - b.y) < 0);
	return (sign(a.x - b.x) < 0);
}

void get_polygon()
{
	int tmp = 0, temp;
	for (int i = 1; i <= n; i++)
	{
		while((tmp >= 2) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	temp = tmp;
	for (int i = n - 1; i >= 1; i--)
	{
		while((tmp > temp) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	len = tmp - 1;
}

Point get_Cross(Point a, Point b, Point c, Point d)
{
	Point t1 = b - a, t2 = d - c;
	return c + d * det(c - a, t1) / det(t2, t1);
}

int main()
{
	double xmax = -1, ymax = -1;
	scanf("%d %lf %lf", &n, &P.x, &P.y);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf %lf", &p[i].x, &p[i].y);
		xmax = max(xmax, p[i].x);
		ymax = max(ymax, p[i].y);
	}
	p[++n] = Point(0, ymax);
	p[++n] = Point(xmax, 0);
	get_polygon();
	ans[len + 1] = ans[1];
	for (int i = 1; i <= len; i++)
		if (sign(det(ans[i], P)) >= 0 && sign(det(P, ans[i + 1])) >= 0)
		{
            //double r1 = det(P - ans[i], ans[i + 1] - ans[i]);
            //double r2 = det(ans[i + 1] - ans[i], Point(0, 0) - ans[i]);
			now = get_Cross(ans[i], ans[i + 1], Point(0, 0), P);
			answer = min(answer, P.length() / now.length());
			//printf("%.8lf\n", P.length() / now.length());
			//printf("%.8lf\n", r1 / r2 + 1);
			//return 0;
		}
	printf("%.8lf\n", answer);
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;

const double eps = 1e-12, pi = 3.14159265358979323846264;
const int maxn = 100086;
double answer = 1e10;
int n, len;

int sign(double u)
{
	if (fabs(u) < eps) return 0;
	if (u > 0) return 1;
	return -1;
}

struct Point
{
	double x, y;

	Point(double x1 = 0, double y1 = 0)
	{
		x = x1;
		y = y1;
	}

	friend Point operator + (Point a, Point b)
	{
		return Point(a.x + b.x, a.y + b.y);
	}

	friend Point operator - (Point a, Point b)
	{
		return Point(a.x - b.x, a.y - b.y);
	}

	friend Point operator * (Point a, double b)
	{
		return Point(a.x * b, a.y * b);
	}

	friend Point operator / (Point a, double b)
	{
		return Point(a.x / b, a.y / b);
	}

	friend bool operator == (Point a, Point b)
	{
		if (sign(a.x - b.x) != 0) return 0;
		if (sign(a.y - b.y) != 0) return 0;
		return 1;
	}

	double length()
	{
		return sqrt(x * x + y * y);
	}
}p[maxn], ans[maxn], P, now;

double det(Point a, Point b)
{
	return a.x * b.y - a.y * b.x;
}

double dot(Point a, Point b)
{
	return a.x * b.x + a.y * b.y;
}

double dist(Point a,Point b)
{
	Point c = a - b;
	return c.length();
}

bool cmp(Point a, Point b)
{
	if (sign(a.x - b.x) == 0)
		return (sign(a.y - b.y) < 0);
	return (sign(a.x - b.x) < 0);
}

void get_polygon()
{
	int tmp = 0, temp;
	sort(p + 1, p + 1 + n, cmp);
	for (int i = 1; i <= n; i++)
	{
		while((tmp >= 2) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	temp = tmp;
	for (int i = n - 1; i >= 1; i--)
	{
		while((tmp > temp) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	len = tmp - 1;
}

Point get_Cross(Point a, Point b, Point c, Point d)
{
	Point t1 = b - a, t2 = d - c;
	return c + d * det(c - a, t1) / det(t2, t1);
}

int main()
{
	double xmax = -1, ymax = -1;
	scanf("%d %lf %lf", &n, &P.x, &P.y);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf %lf", &p[i].x, &p[i].y);
		xmax = max(xmax, p[i].x);
		ymax = max(ymax, p[i].y);
	}
	p[++n] = Point(0, ymax);
	p[++n] = Point(xmax, 0);
	get_polygon();
	ans[len + 1] = ans[1];
	for (int i = 1; i <= len; i++)
		if (sign(det(ans[i], P)) >= 0 && sign(det(P, ans[i + 1])) >= 0)
		{
            //double r1 = det(P - ans[i], ans[i + 1] - ans[i]);
            //double r2 = det(ans[i + 1] - ans[i], Point(0, 0) - ans[i]);
			now = get_Cross(ans[i], ans[i + 1], Point(0, 0), P);
			printf("%.8lf\n", P.length() / now.length());
			//answer = min(answer, P.length() / now.length());
			//printf("%.8lf\n", r1 / r2 + 1);
			return 0;
		}
	return 0;
}


#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <cmath>
using namespace std;

const double eps = 1e-12, pi = 3.14159265358979323846264;
const int maxn = 100086;
double answer = 1e10;
int n, len;

int sign(double u)
{
	if (fabs(u) < eps) return 0;
	if (u > 0) return 1;
	return -1;
}

struct Point
{
	double x, y;

	Point(double x1 = 0, double y1 = 0)
	{
		x = x1;
		y = y1;
	}

	friend Point operator + (Point a, Point b)
	{
		return Point(a.x + b.x, a.y + b.y);
	}

	friend Point operator - (Point a, Point b)
	{
		return Point(a.x - b.x, a.y - b.y);
	}

	friend Point operator * (Point a, double b)
	{
		return Point(a.x * b, a.y * b);
	}

	friend Point operator / (Point a, double b)
	{
		return Point(a.x / b, a.y / b);
	}

	friend bool operator == (Point a, Point b)
	{
		if (sign(a.x - b.x) != 0) return 0;
		if (sign(a.y - b.y) != 0) return 0;
		return 1;
	}

	double length()
	{
		return sqrt(x * x + y * y);
	}
}p[maxn], ans[maxn], P, now;

double det(Point a, Point b)
{
	return a.x * b.y - a.y * b.x;
}

double dot(Point a, Point b)
{
	return a.x * b.x + a.y * b.y;
}

double dist(Point a,Point b)
{
	Point c = a - b;
	return c.length();
}

bool cmp(Point a, Point b)
{
	if (sign(a.x - b.x) == 0)
		return (sign(a.y - b.y) < 0);
	return (sign(a.x - b.x) < 0);
}

void get_polygon()
{
	int tmp = 0, temp;
	for (int i = 1; i <= n; i++)
	{
		while((tmp >= 2) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	temp = tmp;
	for (int i = n - 1; i >= 1; i--)
	{
		while((tmp > temp) && (sign(det(ans[tmp] - ans[tmp - 1], p[i] - ans[tmp - 1])) <= 0)) tmp--;
		ans[++tmp] = p[i];
	}
	len = tmp - 1;
}

Point get_Cross(Point a, Point b, Point c, Point d)
{
	Point t1 = b - a, t2 = d - c;
	return c + d * det(c - a, t1) / det(t2, t1);
}

int main()
{
	double xmax = -1, ymax = -1;
	scanf("%d %lf %lf", &n, &P.x, &P.y);
	for (int i = 1; i <= n; i++)
	{
		scanf("%lf %lf", &p[i].x, &p[i].y);
		xmax = max(xmax, p[i].x);
		ymax = max(ymax, p[i].y);
	}
	p[++n] = Point(0, ymax);
	p[++n] = Point(xmax, 0);
	get_polygon();
	ans[len + 1] = ans[1];
	for (int i = 1; i <= len; i++)
		if (sign(det(ans[i], P)) >= 0 && sign(det(P, ans[i + 1])) >= 0)
		{
            //double r1 = det(P - ans[i], ans[i + 1] - ans[i]);
            //double r2 = det(ans[i + 1] - ans[i], Point(0, 0) - ans[i]);
			now = get_Cross(ans[i], ans[i + 1], Point(0, 0), P);
			answer = min(answer, P.length() / now.length());
			//printf("%.8lf\n", P.length() / now.length());
			//printf("%.8lf\n", r1 / r2 + 1);
			//return 0;
		}
	printf("%.8lf\n", answer);
	return 0;
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  return res;
}

int rmq(int f, int t) {
  int k = -1;
  for (int s = t - f + 1; s; s >>= 1) ++k;
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  std::ios::sync_with_stdio(0);
  std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::sort(sa, sa + n, cmp);
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = 31 - __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::sort(sa, sa + n, cmp);
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  return res;
}

int rmq(int f, int t) {
  int k = std::__lg(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m - 1, lcp[m]);
  solve(m + 1, t, lcp[m]);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  s[an].c = 1;
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  n = an + bn + cn + 2;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::sort(sa, sa + n, cmp);
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n; ++i) dp[0][i] = lcp[i];
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 0);
  assert(s[sa[1]].c == 1);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], bucket[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = 31 - __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp2(int i, int j) {
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  int rn = 255;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::fill(bucket, bucket + rn, 0);
    for (int i = 0; i < n; ++i) ++bucket[rank[i]];
    tmp[0] = bucket[0];
    for (int i = 1; i < rn; ++i) tmp[i] = tmp[i - 1] + bucket[i];
    for (int i = 0; i < n; ++i) sa[--tmp[rank[i]]] = i;
    for (int i = 0; i < rn; ++i)
      std::sort(sa + tmp[i], sa + tmp[i] + bucket[i], cmp2);
    tmp[0] = 0;
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
    rn = tmp[n - 1] + 1;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  std::ios::sync_with_stdio(0);
  std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::sort(sa, sa + n, cmp);
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = 31 - __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::sort(sa, sa + n, cmp);
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], bucket[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = 31 - __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  int rn = 255;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    std::fill(bucket, bucket + rn, 0);
    for (int i = 0; i < n; ++i) ++bucket[rank[i]];
    tmp[0] = bucket[0];
    for (int i = 1; i < rn; ++i) tmp[i] = tmp[i - 1] + bucket[i];
    for (int i = 0; i < n; ++i) sa[--tmp[rank[i]]] = i;
    for (int i = 0; i < rn; ++i)
      std::sort(sa + tmp[i], sa + tmp[i] + bucket[i], cmp);
    tmp[0] = 0;
    for (int i = 1; i < n; ++i)
      tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i)
      rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
    rn = tmp[n - 1] + 1;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

const int N = 300010;
const int MOD = 1e9 + 7;

struct xxx {
  int id;
  char c;
} s[N];

std::string a, b, c;

int gap, n;
int sa[N], lcp[N], rank[N], tmp[N], bucket[N], cnt[N][3], ans[N], dp[19][N], fw[N];

void update(int i, int v) {
  while (i < N) {
    fw[i] = (fw[i] + v) % MOD;
    i += i & -i;
  }
}

int query(int i) {
  int res = 0;
  while (i) {
    res = (res + fw[i]) % MOD;
    i -= i & -i;
  }
  if (res < 0) res += MOD;
  return res;
}

int rmq(int f, int t) {
  int k = 31 - __builtin_clz(t - f + 1);
  int x = dp[k][f];
  int y = dp[k][t - (1 << k) + 1];
  if (lcp[x] < lcp[y]) return x;
  return y;
}

void solve(int f, int t, int h) {
  if (t - f + 1 < 3) return;
  int m = rmq(f, t - 1);
  int c0 = cnt[t][0] - cnt[f - 1][0];
  int c1 = cnt[t][1] - cnt[f - 1][1];
  int c2 = cnt[t][2] - cnt[f - 1][2];
  int v = lcp[m];
  int num = 1ll * c0 * c1 % MOD * c2 % MOD;
  update(v + 1, -num);
  update(h + 1, num);
  solve(f, m, v);
  solve(m + 1, t, v);
}

bool cmp2(int i, int j) {
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

bool cmp(int i, int j) {
  if (rank[i] != rank[j]) return rank[i] < rank[j];
  i += gap;
  j += gap;
  if (i < n && j < n) return rank[i] < rank[j];
  return i > j;
}

int main() {
  //assert(freopen("input.txt", "r", stdin));
  //assert(freopen("output.txt", "w", stdout));
  //std::ios::sync_with_stdio(0);
  //std::cin.tie(0);
  std::cin >> a >> b >> c;
  int an = int(a.size()), bn = int(b.size()), cn = int(c.size());
  for (int i = 0; i < an; ++i)
    s[i].id = 0, s[i].c = a[i];
  for (int i = 0; i < bn; ++i)
    s[i + an + 1].id = 1, s[i + an + 1].c = b[i];
  for (int i = 0; i < cn; ++i)
    s[i + an + bn + 2].id = 2, s[i + an + bn + 2].c = c[i];
  s[an].c = 1;
  s[an + bn + 1].c = 2;
  n = an + bn + cn + 2;
  int rn = 255;
  for (int i = 0; i < n; ++i) {
    sa[i] = i;
    rank[i] = s[i].c;
  }
  for (gap = 1; ; gap <<= 1) {
    int p = 0;
    for (int i = n - 1; i + gap >= n; --i) tmp[p++] = i;
    std::fill(bucket, bucket + rn, 0);
    for (int i = 0; i + gap < n; ++i) ++bucket[rank[i + gap]];
    for (int i = 1; i < rn; ++i) bucket[i] += bucket[i - 1];
    for (int i = 0; i + gap < n; ++i) tmp[--bucket[rank[i + gap]] + p] = i;
    std::fill(bucket, bucket + rn, 0);
    for (int i = 0; i < n; ++i) ++bucket[rank[i]];
    for (int i = 1; i < rn; ++i) bucket[i] += bucket[i - 1];
    for (int i = n - 1; i >= 0; --i) sa[--bucket[rank[tmp[i]]]] = tmp[i];
    tmp[0] = 0;
    for (int i = 1; i < n; ++i) tmp[i] = tmp[i - 1] + cmp(sa[i - 1], sa[i]);
    for (int i = 0; i < n; ++i) rank[sa[i]] = tmp[i];
    if (tmp[n - 1] == n - 1) break;
    rn = tmp[n - 1] + 1;
  }
  for (int i = 0, k = 0; i < n; ++i) {
    if (rank[i] == n - 1) continue;
    for (int j = sa[rank[i] + 1]; s[i + k].c == s[j + k].c; )
      ++k;
    lcp[rank[i]] = k;
    if (k) --k;
  }
  for (int i = 0; i < n - 1; ++i) dp[0][i] = i;
  for (int j = 1; 1 << j < n; ++j)
    for (int i = 0; i + (1 << j) - 1 < n - 1; ++i) {
      int x = dp[j - 1][i];
      int y = dp[j - 1][i + (1 << (j - 1))];
      dp[j][i] = lcp[x] < lcp[y] ? x : y;
    }
  assert(s[sa[0]].c == 1);
  assert(s[sa[1]].c == 2);
  for (int i = 2; i < n; ++i) {
    cnt[i][0] = cnt[i - 1][0];
    cnt[i][1] = cnt[i - 1][1];
    cnt[i][2] = cnt[i - 1][2];
    ++cnt[i][s[sa[i]].id];
  }
  int sz = std::min(an, std::min(bn, cn));
  solve(2, n - 1, 0);
  for (int i = 1; i <= sz; ++i)
    std::cout << query(i) << ' ';
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5, P = 1e9 + 7;
int n, len = P;
int r[maxn][3], c[maxn], a[maxn], ans[maxn];
char s[maxn];
vector<int> G[maxn * 2];
namespace SAM {
	struct node {
        int val, par;
        int ch[26];
    } t[maxn * 2];
    int last = 1, root = 1, sz = 1;
    int nw(int x)
    {
        t[++sz].val = x;
        return sz;
    }
    void extend(int c, int tt)
    {
        int p = last, np = nw(t[p].val + 1);
        while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
        if(!p) t[np].par = root;
        else
        {
            int q = t[p].ch[c];
            if(t[q].val == t[p].val + 1) t[np].par = q;
            else
            {
                int nq = nw(t[p].val + 1);
                memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                t[nq].par = t[q].par;
                t[q].par = t[np].par = nq;
                while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
            }
        }
        last = np;
        r[last][tt] = 1;
    }
} using namespace SAM;
void dfs(int u) {
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		dfs(v);
		for(int j = 0; j < 3; ++j) {
			r[u][j] += r[v][j];
		}
	}
}
int main() {
	for(int i = 0; i < 3; ++i) {
		scanf("%s", s + 1);
		n = strlen(s + 1);
		len = min(len, n);
		last = root;
		for(int j = 1; j <= n; ++j) {
			extend(s[j] - 'a', i);
		}
	}
	for(int i = 1; i <= sz; ++i) {
		G[t[i].par].push_back(i);
	}
	dfs(root);
	for(int i = 1; i <= sz; ++i) {
		int L = t[t[i].par].val + 1, R = t[i].val, d = 1LL * r[i][0] * r[i][1] % P * r[i][2] % P;
		ans[L] = (ans[L] + d) % P;
		ans[R + 1] = (ans[R + 1] - d + P) % P;
	}
	for(int i = 1; i <= len; ++i) {
		ans[i] = (ans[i] + ans[i - 1]) % P;
		printf("%d ", ans[i]);
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5, P = 1e9 + 7;
int n, len = P;
int r[maxn][3], c[maxn], a[maxn], ans[maxn];
char s[maxn];
vector<int> G[maxn * 2];
namespace SAM {
	struct node {
        int val, par;
        int ch[26];
    } t[maxn * 2];
    int last = 1, root = 1, sz = 1;
    int nw(int x)
    {
        t[++sz].val = x;
        return sz;
    }
    void extend(int c, int tt)
    {
        int p = last, np = nw(t[p].val + 1);
        while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
        if(!p) t[np].par = root;
        else
        {
            int q = t[p].ch[c];
            if(t[q].val == t[p].val + 1) t[np].par = q;
            else
            {
                int nq = nw(t[p].val + 1);
                memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                t[nq].par = t[q].par;
                t[q].par = t[np].par = nq;
                while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
            }
        }
        last = np;
        r[last][tt] = 1;
    }
} using namespace SAM;
void dfs(int u) {
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		dfs(v);
		for(int j = 0; j < 3; ++j) {
			r[u][j] += r[v][j];
		}
	}
}
int main() {
	for(int i = 0; i < 3; ++i) {
		scanf("%s", s + 1);
		n = strlen(s + 1);
		len = min(len, n);
		last = root;
		for(int j = 1; j <= n; ++j) {
			extend(s[j] - 'a', i);
		}
	}
	for(int i = 1; i <= sz; ++i) {
		G[t[i].par].push_back(i);
	}
	dfs(root);
	for(int i = 1; i <= sz; ++i) {
		int L = t[t[i].par].val + 1, R = t[i].val, d = 1LL * r[i][0] * r[i][1] % P * r[i][2] % P;
		ans[L] += d;
		ans[R + 1] -= d;
	}
	for(int i = 1; i <= len; ++i) {
		ans[i] = (ans[i] + ans[i - 1]) % P;
		printf("%d ", ans[i]);
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 6e5 + 5, P = 1e9 + 7;
int n, len = P;
int r[maxn][3], c[maxn], a[maxn], ans[maxn];
char s[maxn];
vector<int> G[maxn * 2];
namespace SAM {
	struct node {
        int val, par;
        int ch[26];
    } t[maxn * 2];
    int last = 1, root = 1, sz = 1;
    int nw(int x)
    {
        t[++sz].val = x;
        return sz;
    }
    void extend(int c, int tt)
    {
        int p = last, np = nw(t[p].val + 1);
        while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
        if(!p) t[np].par = root;
        else
        {
            int q = t[p].ch[c];
            if(t[q].val == t[p].val + 1) t[np].par = q;
            else
            {
                int nq = nw(t[p].val + 1);
                memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                t[nq].par = t[q].par;
                t[q].par = t[np].par = nq;
                while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
            }
        }
        last = np;
        r[last][tt] = 1;
    }
} using namespace SAM;
void dfs(int u) {
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		dfs(v);
		for(int j = 0; j < 3; ++j) {
			r[u][j] += r[v][j];
		}
	}
}
int main() {
	for(int i = 0; i < 3; ++i) {
		scanf("%s", s + 1);
		n = strlen(s + 1);
		len = min(len, n);
		last = root;
		for(int j = 1; j <= n; ++j) {
			extend(s[j] - 'a', i);
		}
	}
	for(int i = 1; i <= sz; ++i) {
		G[t[i].par].push_back(i);
	}
	dfs(root);
	for(int i = 1; i <= sz; ++i) {
		int L = t[t[i].par].val + 1, R = t[i].val, d = 1LL * r[i][0] * r[i][1] % P * r[i][2] % P;
		ans[L] = (ans[L] + d) % P;
		ans[R + 1] = (ans[R + 1] - d + P) % P;
	}
	for(int i = 1; i <= len; ++i) {
		ans[i] = (ans[i] + ans[i - 1]) % P;
		printf("%d ", ans[i]);
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5, P = 1e9 + 7;
int n, len = P;
int r[maxn][3], c[maxn], a[maxn], ans[maxn];
char s[maxn];
vector<int> G[maxn * 2];
namespace SAM {
	struct node {
        int val, par;
        int ch[26];
    } t[maxn * 2];
    int last = 1, root = 1, sz = 1;
    int nw(int x)
    {
        t[++sz].val = x;
        return sz;
    }
    void extend(int c, int tt)
    {
        int p = last, np = nw(t[p].val + 1);
        while(p && !t[p].ch[c]) t[p].ch[c] = np, p = t[p].par;
        if(!p) t[np].par = root;
        else
        {
            int q = t[p].ch[c];
            if(t[q].val == t[p].val + 1) t[np].par = q;
            else
            {
                int nq = nw(t[p].val + 1);
                memcpy(t[nq].ch, t[q].ch, sizeof(t[q].ch));
                t[nq].par = t[q].par;
                t[q].par = t[np].par = nq;
                while(p && t[p].ch[c] == q) t[p].ch[c] = nq, p = t[p].par;
            }
        }
        last = np;
        r[last][tt] = 1;
    }
} using namespace SAM;
void dfs(int u) {
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		dfs(v);
		for(int j = 0; j < 3; ++j) {
			r[u][j] += r[v][j];
		}
	}
}
int main() {
	for(int i = 0; i < 3; ++i) {
		scanf("%s", s + 1);
		n = strlen(s + 1);
		len = min(len, n);
		last = root;
		for(int j = 1; j <= n; ++j) {
			extend(s[j] - 'a', i);
		}
	}
	for(int i = 1; i <= sz; ++i) {
		G[t[i].par].push_back(i);
	}
	dfs(root);
	for(int i = 1; i <= sz; ++i) {
		int L = t[t[i].par].val + 1, R = t[i].val, d = 1LL * r[i][0] * r[i][1] % P * r[i][2] % P;
		ans[L] = (ans + d) % P;
		ans[R + 1] = (ans[R + 1] - d + P) % P;
	}
	for(int i = 1; i <= len; ++i) {
		ans[i] = (ans[i] + ans[i - 1]) % P;
		printf("%d ", ans[i]);
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;

struct Sam
{
    int l, fa, son[29];
    int r[3];
};
const int Mo = 1000000007;
const int maxlong = int(1e9);
const int N = int(3e5)+5;
char s[N];
Sam S[N<<1];
int tot , last , n , len;
int du[N<<1];
bool v[N<<1];
LL Ans[N];

void add(int x,int b)
{
    int p = ++tot , bj = last;
    S[p].l = S[bj].l + 1;
    for(; bj!=-1 && !S[bj].son[x]; bj=S[bj].fa) S[bj].son[x] = p;
    if (bj == -1) S[p].fa = 0;else
    if (S[bj].l+1 == S[S[bj].son[x]].l) S[p].fa = S[bj].son[x];else
    {
        int r = ++tot , q = S[bj].son[x];
        S[r] = S[q];
        fo(k,0,2) S[r].r[k] = 0;
        S[p].fa = S[q].fa = r;
        S[r].l = S[bj].l+1;
        for(; bj!=-1 && S[bj].son[x]==q; bj=S[bj].fa) S[bj].son[x] = r;
    }
    S[last = p].r[b] ++;
}

void Init()
{
    n = maxlong;
    S[0].fa = -1;
    tot = last = 0;
    fo(j,0,2)
    {
        scanf("%s",s+1);
        len = strlen(s+1);
        n = min(n , len);
        fo(i,1,len) add(s[i] - 'a' , j);
        add('z'-'a'+j+1 , j);
    }
}

void Dfs(int x)
{
    if (!v[x]) return;
    v[x] = 0;
    if (S[x].fa > 0)
    {
        fo(k,0,2) (S[S[x].fa].r[k] += S[x].r[k]) %= Mo;
        du[S[x].fa] --;
        if (!du[S[x].fa]) Dfs(S[x].fa);
    }
}

void Work()
{
    fo(i,1,tot) du[S[i].fa] ++ , v[i] = 1;
    fo(i,1,tot)
        if (!du[i]) Dfs(i);
    fo(i,1,tot)
    {
        int tmp = LL(S[i].r[0]) * S[i].r[1] % Mo * S[i].r[2] % Mo;
        (Ans[S[i].l] += tmp) %= Mo;
        (Ans[S[S[i].fa].l] -= tmp) %= Mo;
    }
    fd(i,n,1) Ans[i] = ((Ans[i] + Ans[i+1]) % Mo + Mo) % Mo;
    fo(i,1,n) printf("%d ",Ans[i]);
}

int main()
{

    Init();
    Work();

    return 0;
}


#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;

struct Sam
{
    int l, fa, son[26];
    int r[3];
};
const int Mo = 1000000007;
const int maxlong = int(1e9);
const int N = int(3e5)+5;
char s[N];
Sam S[N<<1];
int tot , last , n , len;
int du[N<<1];
bool v[N<<1];
LL Ans[N];

void add(int x,int b)
{
    int p = ++tot , bj = last;
    S[p].l = S[bj].l + 1;
    for(; bj!=-1 && !S[bj].son[x]; bj=S[bj].fa) S[bj].son[x] = p;
    if (bj == -1) S[p].fa = 0;else
    if (S[bj].l+1 == S[S[bj].son[x]].l) S[p].fa = S[bj].son[x];else
    {
        int r = ++tot , q = S[bj].son[x];
        S[r] = S[q];
        fo(k,0,3) S[r].r[k] = 0;
        S[p].fa = S[q].fa = r;
        S[r].l = S[bj].l+1;
        for(; bj!=-1 && S[bj].son[x]==q; bj=S[bj].fa) S[bj].son[x] = r;
    }
    S[last = p].r[b] ++;
}

void Init()
{
    n = maxlong;
    S[0].fa = -1;
    tot = last = 0;
    fo(j,0,2)
    {
        scanf("%s",s+1);
        len = strlen(s+1);
        n = min(n , len);
        fo(i,1,len) add(s[i] - 'a' , j);
    }
}

void Dfs(int x)
{
    if (!v[x]) return;
    v[x] = 0;
    if (S[x].fa > 0)
    {
        fo(k,0,2) (S[S[x].fa].r[k] += S[x].r[k]) %= Mo;
        du[S[x].fa] --;
        if (!du[S[x].fa]) Dfs(S[x].fa);
    }
}

void Work()
{
    fo(i,1,tot) du[S[i].fa] ++ , v[i] = 1;
    fo(i,1,tot)
        if (!du[i]) Dfs(i);
    fo(i,1,tot)
    {
        int tmp = LL(S[i].r[0]) * S[i].r[1] % Mo * S[i].r[2] % Mo;
        (Ans[S[i].l] += tmp) %= Mo;
        (Ans[S[S[i].fa].l] -= tmp) %= Mo;
    }
    fd(i,n,1) Ans[i] = ((Ans[i] + Ans[i+1]) % Mo + Mo) % Mo;
    fo(i,1,n) printf("%d ",Ans[i]);
}

int main()
{

    Init();
    Work();

    return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 3 * 1e6 + 10000;

class suffixVert{
public:
	int l, r, suff, par, depth;
	int g[30];
    int d[30];
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
};

suffixVert z[maxn];
int sz, real_size;

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (char c = 0; c <= 29; ++c) {
    	if (z[v].g[(int)c] != -1) {
    		calc_depth(z[v].g[(int)c], cur);
            for (int i = z[z[v].g[(int)c]].l; i < z[z[v].g[(int)c]].r; ++i)
                z[v].d[(int)s[i]] += 1;
            z[v].d[0] += z[z[v].g[(int)c]].d[0];
            z[v].d[1] += z[z[v].g[(int)c]].d[1];
            z[v].d[2] += z[z[v].g[(int)c]].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] += tmp * tmp2 * tmp3;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

    for (char c = 0; c <= 29; ++c)
        if (z[v].g[(int)c] != -1)
            dfs(z[v].g[(int)(c)], cur);
}

int main()
{
    ios_base::sync_with_stdio(0);
    string s1, s2, s3;
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 4 * 1e6 + 10000;

class suffixVert{
public:
	int l, r, suff, par, depth;
	int g[30];
    int d[30];
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
};

suffixVert z[maxn];
int sz, real_size;

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (char c = 0; c <= 29; ++c) {
    	if (z[v].g[(int)c] != -1) {
    		calc_depth(z[v].g[(int)c], cur);
            for (int i = z[z[v].g[(int)c]].l; i < z[z[v].g[(int)c]].r; ++i)
                z[v].d[(int)s[i]] += 1;
            z[v].d[0] += z[z[v].g[(int)c]].d[0];
            z[v].d[1] += z[z[v].g[(int)c]].d[1];
            z[v].d[2] += z[z[v].g[(int)c]].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] += tmp * tmp2 * tmp3;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

    for (char c = 0; c <= 29; ++c)
        if (z[v].g[(int)c] != -1)
            dfs(z[v].g[(int)(c)], cur);
}

int main()
{
    ios_base::sync_with_stdio(0);
    string s1, s2, s3;
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 1e6 + 15;

class suffixVert{
public:
	int l, r, suff, par, depth;
	int g[33];
    int d[33];
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par; memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));}
};

suffixVert z[maxn];
int sz, real_size;

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (char c = 0; c <= 32; ++c) {
    	if (z[v].g[(int)c] != -1) {
    		calc_depth(z[v].g[(int)c], cur);
            for (int i = z[z[v].g[(int)c]].l; i < z[z[v].g[(int)c]].r; ++i)
                z[v].d[(int)s[i]] += 1;
//            z[v].d[(int)c] += 1;
            for (char c2 = 0; c2 <= 32; ++c2) {
                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
            }
        }
    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] += tmp * tmp2 * tmp3;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

    for (char c = 0; c <= 32; ++c)
        if (z[v].g[(int)c] != -1)
            dfs(z[v].g[(int)(c)], cur);
}

int main()
{
    ios_base::sync_with_stdio(0);
    string s1, s2, s3;
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 4;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 4;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 4;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

	sz = 1;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
//    cerr << "size = " << sz << endl;
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>
#include <set>

using namespace std;

string s;

const int maxn = 2 * 1e6;

const int md = 1e9 + 7;

class suffixVert{
public:
	int l, r, suff, par, depth;
//	int g[30];
//    int d[30];
    map<int, int> g;
    map<int, int> d;
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0;/* memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par;/*memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
};

suffixVert z[maxn];
int sz, real_size;
int dyn[maxn][3];

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
    if (z[v].g.find((int)c) == z[v].g.end())
        return -1;
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int t[maxn * 4];

int calc_d(int l, int r, int c) {
    if (l == 0)
        return dyn[r - 1][c];
//    cerr << l << " " << r << " " << c << " " << dyn[r - 1][c] - dyn[l - 1][c] << endl;
    return dyn[r - 1][c] - dyn[l - 1][c];
}

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it) {
//    for (char c = 0; c <= 29; ++c) {
//    	if (next(v, c) != -1) {
//            int to = next(v, c);
            int to = it->second;
            char c = it->first;
    		calc_depth(to, cur);
/*            int tmp[3];
            tmp[0] = tmp[1] = tmp[2] = 0;
            for (int i = z[to].l; i < z[to].r; ++i)
                if ((int)s[i] <= 2)
                    tmp[s[i]] += 1;*/
            z[v].d[0] += calc_d(z[to].l, z[to].r, 0);
            z[v].d[1] += calc_d(z[to].l, z[to].r, 1);
            z[v].d[2] += calc_d(z[to].l, z[to].r, 2);
//            cerr << calc_d(z[to].l, z[to].r, 2) << " " << tmp[2] << endl;
            z[v].d[0] += z[to].d[0];
            z[v].d[1] += z[to].d[1];
            z[v].d[2] += z[to].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
//    }
}

void update (int v, int tl, int tr, int l, int r, int add) {
	if (l > r)
		return;
//    assert(l == r);
//    cerr << v << " " << l << " " << r << " " << tl << " " << tr << endl;
//    return;
	if (l == tl && tr == r)
		t[v] = (t[v] + add) % md;
	else {
		int tm = (tl + tr) / 2;
		update (v * 2, tl, tm, l, min(r, tm), add);
		update (v * 2 + 1, tm + 1, tr, max(l, tm + 1), r, add);
	}
}
int get (int v, int tl, int tr, int pos) {
	if (tl == tr)
		return t[v];
	int tm = (tl + tr) / 2;
	if (pos <= tm)
		return (t[v] + get (v*2, tl, tm, pos)) % md;
	else
		return (t[v] + get (v*2+1, tm+1, tr, pos)) % md;
}

void dfs(int v, int cur) {
//    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp1 = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp1 > 0 && tmp2 > 0 && tmp3 > 0 && z[v].len() > 0) {
/*            node tmp;
            tmp.l = cur;
            tmp.r = cur + z[v].len();*/
            int tmp_value = (tmp1 * 1ll * tmp2 * 1ll * tmp3) % md;
            update(1, 0, (1 << 20), cur, cur + z[v].len() - 1, tmp_value);
//            ans.push_back(tmp);
//            l[cur + i - z[v].l] = (l[cur + i - z[v].l] + tmp * 1ll * tmp2 * 1ll * tmp3) % md;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
//    }
    cur += z[v].len();

//    for (char c = 0; c <= 29; ++c)
    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it)
//        if (next(v, c) != -1)
//            dfs(next(v, c), cur);
        dfs(it->second, cur);
}

string s1, s2, s3;
int main()
{
    ios_base::sync_with_stdio(0);
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

    if (s[0] <= 2)
        dyn[0][s[0]] = 1;
    for (int i = 1; i < s.size(); ++i) {
        for (int j = 0; j <= 2; ++j)
            dyn[i][j] = dyn[i - 1][j];
        if (s[i] <= 2)
            dyn[i][s[i]]++;
    }
/*    for (int i = 0; i < s.size(); ++i)
        cerr << (int)s[i] << " ";
    cerr << endl;
    for (int i = 0; i < s.size(); ++i)
        cerr << dyn[i][0] << " " << dyn[i][1] << " " << dyn[i][2] << endl;*/

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    cerr << sz << endl;
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

//    sort(ans.begin(), ans.end(), cmp);

//    for (int i = 0; i < ans.size(); ++i)
//        cerr << ans[i].l << " " << ans[i].r << " " << ans[i].value << endl;

    long long cur = 0;
    int p = 0;
    set<pair<int, long long> > z_s;
    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i) {
/*        while (z_s.size() > 0 && z_s.begin()->first <= i) {
            cur -= z_s.begin()->second;
            z_s.erase(z_s.begin());
        }
        while (p < ans.size() && ans[p].l <= i) {
            cur += ans[p].value;
            z_s.insert(make_pair(ans[p].r, ans[p].value));
            ++p;
        }
        cout << cur % md << " ";*/
        cout << get(1, 0, (1<<20), i) << " ";
    }

//    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
//        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 2 * 1e6;

class suffixVert{
public:
	int l, r, suff, par, depth;
//	int g[30];
//    int d[30];
    map<int, int> g;
    map<int, int> d;
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0;/* memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par;/*memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
};

suffixVert z[maxn];
int sz, real_size;

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
    if (z[v].g.find((int)c) == z[v].g.end())
        return -1;
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (char c = 0; c <= 29; ++c) {
    	if (next(v, c) != -1) {
            int to = next(v, c);
    		calc_depth(to, cur);
            for (int i = z[to].l; i < z[to].r; ++i)
                z[v].d[(int)s[i]] += 1;
            z[v].d[0] += z[to].d[0];
            z[v].d[1] += z[to].d[1];
            z[v].d[2] += z[to].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] += tmp * tmp2 * tmp3;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

    for (char c = 0; c <= 29; ++c)
        if (next(v, c) != -1)
            dfs(next(v, c), cur);
}

string s1, s2, s3;
int main()
{
    ios_base::sync_with_stdio(0);
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 2 * 1e6;

const int md = 1e9 + 7;

class suffixVert{
public:
	int l, r, suff, par, depth;
//	int g[30];
//    int d[30];
    map<int, int> g;
    map<int, int> d;
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0;/* memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par;/*memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
};

suffixVert z[maxn];
int sz, real_size;
int dyn[maxn][3];

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
    if (z[v].g.find((int)c) == z[v].g.end())
        return -1;
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

int calc_d(int l, int r, int c) {
    if (l == 0)
        return dyn[r - 1][c];
//    cerr << l << " " << r << " " << c << " " << dyn[r - 1][c] - dyn[l - 1][c] << endl;
    return dyn[r - 1][c] - dyn[l - 1][c];
}

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it) {
//    for (char c = 0; c <= 29; ++c) {
//    	if (next(v, c) != -1) {
//            int to = next(v, c);
            int to = it->second;
            char c = it->first;
    		calc_depth(to, cur);
/*            int tmp[3];
            tmp[0] = tmp[1] = tmp[2] = 0;
            for (int i = z[to].l; i < z[to].r; ++i)
                if ((int)s[i] <= 2)
                    tmp[s[i]] += 1;*/
            z[v].d[0] += calc_d(z[to].l, z[to].r, 0);
            z[v].d[1] += calc_d(z[to].l, z[to].r, 1);
            z[v].d[2] += calc_d(z[to].l, z[to].r, 2);
//            cerr << calc_d(z[to].l, z[to].r, 2) << " " << tmp[2] << endl;
            z[v].d[0] += z[to].d[0];
            z[v].d[1] += z[to].d[1];
            z[v].d[2] += z[to].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
//    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] = (l[cur + i - z[v].l] + tmp * 1ll * tmp2 * 1ll * tmp3) % md;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

//    for (char c = 0; c <= 29; ++c)
    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it)
//        if (next(v, c) != -1)
//            dfs(next(v, c), cur);
        dfs(it->second, cur);
}

string s1, s2, s3;
int main()
{
    ios_base::sync_with_stdio(0);
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

    if (s[0] <= 2)
        dyn[0][s[0]] = 1;
    for (int i = 1; i < s.size(); ++i) {
        for (int j = 0; j <= 2; ++j)
            dyn[i][j] = dyn[i - 1][j];
        if (s[i] <= 2)
            dyn[i][s[i]]++;
    }
/*    for (int i = 0; i < s.size(); ++i)
        cerr << (int)s[i] << " ";
    cerr << endl;
    for (int i = 0; i < s.size(); ++i)
        cerr << dyn[i][0] << " " << dyn[i][1] << " " << dyn[i][2] << endl;*/

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    cerr << sz << endl;
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}


#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include <algorithm>
#include <cassert>

using namespace std;

string s;

const int maxn = 2 * 1e6;

const int md = 1e9 + 7;

class suffixVert{
public:
	int l, r, suff, par, depth;
//	int g[30];
//    int d[30];
    map<int, int> g;
    map<int, int> d;
	inline int len() {
		return r - l;
	}
	suffixVert() {suff = -1, par = -1, l = 0, r = 0;/* memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
	suffixVert(int _l, int _r, int _par) {suff = -1, l = _l, r = _r, par = _par;/*memset(g, -1, sizeof(g)); memset(d, 0, sizeof(d));*/}
};

suffixVert z[maxn];
int sz, real_size;
int dyn[maxn][30];

void shrink() {
/*    cerr << "Here" << endl;
    exit(1);
//    double coeff = real_size > 1e5 ? 1.2 : 2;
    double coeff = 2;
    z = (suffixVert *) realloc(z, sizeof(suffixVert) * int(coeff * real_size));
//    for (int i = real_size; i < int(coeff * real_size); ++i)
//        z[i] = suffixVert();
    real_size = int(real_size * coeff);*/
}

inline int next(int v, char c)
{
    if (z[v].g.find((int)c) == z[v].g.end())
        return -1;
	return z[v].g[(int)c];
}

class state{
public:
	int v, pos;
	state() {v = 0, pos = 0;}
	state(int _v, int _pos) { v = _v, pos = _pos;}
};

state pos;

state findState(state st, int l, int r)
{
	while (l < r)
	{
//        assert(st.v >= 0 && st.v <= sz);
//        assert(l >= 0 && l < s.size());
//        assert(r >= 0 && r <= s.size());
		if (st.pos == z[st.v].len())
		{
			st.pos = 0;
			st.v = next(st.v, s[l]);
			if (st.v == -1)
            return st;
		} else {
			if (s[z[st.v].l + st.pos] != s[l])
				return state(-1, -1);
			if (r - l < z[st.v].len() - st.pos)
				return state(st.v, st.pos + r - l);
			l += z[st.v].len() - st.pos;
			st.pos = z[st.v].len();
		}
	}
	return st;
}

int cut_edge(state p)
{
//    cerr << p.v << endl;
//    assert(p.v >= 0 && p.v <= sz);
	if (p.pos == z[p.v].len())
		return p.v;
	if (p.pos == 0)
		return z[p.v].par;
	suffixVert tek = z[p.v];
	int last = sz++;
    if (last >= real_size) shrink();
//    assert(last >= 0 && last <= sz);
	z[last] = suffixVert(tek.l, tek.l + p.pos, tek.par);
//    assert(tek.l + p.pos >= 0 && tek.l + p.pos < s.size());
	z[last].g[(int)s[tek.l + p.pos]] = p.v;
//    assert(tek.par >= 0 && tek.par <= sz);
	z[tek.par].g[(int)s[tek.l]] = last;
//    assert(p.v >= 0 && p.v <= sz);
	z[p.v].par = last;
	z[p.v].l += p.pos;
	return last;
}

int make_link(int v)
{
  //  assert(v >= 0 && v <= sz);
	if (z[v].suff != -1)
		return z[v].suff;
	if (z[v].par == -1)
		return 0;
	int suff_par = make_link(z[v].par);
//    assert(suff_par >= 0 && suff_par <= sz);
//    assert(v >= 0 && v <= sz);
	state tek = findState(state(suff_par, z[suff_par].len()), z[v].l + (z[v].par == 0), z[v].r);
//    cerr << "v == " << v << endl;
    int tmp = cut_edge(tek);
//    cerr << "omg: " << tmp << endl;
	z[v].suff = tmp; // HERE PROBLEM
//    cerr << z[v].suff << endl;
	return z[v].suff;
}

void new_vert(int i)
{
	while(1)
	{
		state npos = findState(pos, i, i + 1);
		if (npos.v != -1)
		{
			pos = npos;
			return;
		}
		int p = cut_edge(pos);
		int last = sz++;
//        cerr << "last: " << last << endl;
        if (last >= real_size) shrink();
//        cerr << "last: " << last << " " << real_size << endl;
		z[last] = suffixVert(i, s.size(), p);
 //       cerr << "p: " << p << endl;
		z[p].g[(int)s[i]] = last;
//        cerr << "p2: " << p << endl;

		pos.v = make_link(p);
        if (pos.v == -1) pos.v = 0;
		pos.pos = z[pos.v].len();
		if (!p)
			break;
	}
}

int it = 0;

int l[maxn];

int calc_d(int l, int r, int c) {
    if (l == 0)
        return dyn[r - 1][c];
//    cerr << l << " " << r << " " << c << " " << dyn[r - 1][c] - dyn[l - 1][c] << endl;
    return dyn[r - 1][c] - dyn[l - 1][c];
}

void calc_depth(int v, int cur) {
    cur += z[v].len();
    z[v].depth = cur;

    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it) {
//    for (char c = 0; c <= 29; ++c) {
//    	if (next(v, c) != -1) {
//            int to = next(v, c);
            int to = it->second;
            char c = it->first;
    		calc_depth(to, cur);
/*            int tmp[3];
            tmp[0] = tmp[1] = tmp[2] = 0;
            for (int i = z[to].l; i < z[to].r; ++i)
                if ((int)s[i] <= 2)
                    tmp[s[i]] += 1;*/
            z[v].d[0] += calc_d(z[to].l, z[to].r, 0);
            z[v].d[1] += calc_d(z[to].l, z[to].r, 1);
            z[v].d[2] += calc_d(z[to].l, z[to].r, 2);
//            cerr << calc_d(z[to].l, z[to].r, 2) << " " << tmp[2] << endl;
            z[v].d[0] += z[to].d[0];
            z[v].d[1] += z[to].d[1];
            z[v].d[2] += z[to].d[2];
//            z[v].d[(int)c] += 1;
//            for (char c2 = 0; c2 <= 29; ++c2) {
//                z[v].d[(int)c2] += z[z[v].g[(int)c]].d[(int)c2];
//            }
        }
//    }
}

void dfs(int v, int cur) {
    for (int i = z[v].l; i < z[v].r; ++i) {
//        if (z[v].d[0] <= 2 || z[v].d[1] <= 1 || z[v].d[2] == 0)
//            continue;
//        cerr << v << char(s[i] - 4 + 'a') << " " << cur + i - z[v].l + 1 << " " << z[v].d[0] << " " << z[v].d[1] << " " << z[v].d[2] << endl;
        long long tmp = (z[v].d[0] - z[v].d[1]);
        long long tmp2 = (z[v].d[1] - z[v].d[2]);
        long long tmp3 = z[v].d[2];
//        cerr << cur + i - z[v].l << " " << tmp << " " << tmp2 << " " << tmp3 << endl;
        if (tmp > 0 && tmp2 > 0 && tmp3 > 0) {
            l[cur + i - z[v].l] = (l[cur + i - z[v].l] + tmp * 1ll * tmp2 * 1ll * tmp3) % md;
        }
//       l[cur + i - z[v].l + 1] += (z[v].d[0] - z[v].d[1] - z) * (z[v].d[1] - 1) * (z[v].d[2] - 0);
    }
    cur += z[v].len();

//    for (char c = 0; c <= 29; ++c)
    for (map<int, int>::const_iterator it = z[v].g.begin(); it != z[v].g.end(); ++it)
//        if (next(v, c) != -1)
//            dfs(next(v, c), cur);
        dfs(it->second, cur);
}

string s1, s2, s3;
int main()
{
    ios_base::sync_with_stdio(0);
    cin >> s1 >> s2 >> s3;

    int st_size = maxn;

    real_size = st_size;
//    z = (suffixVert *) malloc(sizeof(suffixVert) * real_size);
//    cerr << z << endl;
//    for (int i = 0; i < real_size; ++i)
//        z[i] = suffixVert();
    z[0] = suffixVert();

    for (int i = 0; i < s1.size(); ++i)
        s1[i] = s1[i] - 'a' + 3;
    for (int i = 0; i < s2.size(); ++i)
        s2[i] = s2[i] - 'a' + 3;
    for (int i = 0; i < s3.size(); ++i)
        s3[i] = s3[i] - 'a' + 3;

    s = s1;
    s.push_back(2);
    s += s2;
    s.push_back(1);
    s += s3;
    s.push_back(0);

    dyn[0][s[0]] = 1;
    for (int i = 1; i < s.size(); ++i) {
        for (int j = 0; j <= 2; ++j)
            dyn[i][j] = dyn[i - 1][j];
        dyn[i][s[i]]++;
    }
/*    for (int i = 0; i < s.size(); ++i)
        cerr << (int)s[i] << " ";
    cerr << endl;
    for (int i = 0; i < s.size(); ++i)
        cerr << dyn[i][0] << " " << dyn[i][1] << " " << dyn[i][2] << endl;*/

	sz = 1;

    cerr << s.size() << endl;

	for (int i = 0; i < s.size(); ++i) {
//        cerr << i << " " << int(s[0]) << " " << sz << endl;
		new_vert(i);
//        cerr << i << endl;
    }
    cerr << sz << endl;
    calc_depth(0, 0);

//    for (int i = 0; i <= 34; ++i)
//        cerr << "i == " << z[0].d[i] << endl;

    cerr << "size = " << sz << endl;
    dfs(0, 0);

    for (int i = 0; i < min(s1.size(), min(s2.size(), s3.size())); ++i)
        cout << l[i] << " ";

	return 0;
}