#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
			if (EXSAM_Pool[i].step > 300000 || EXSAM_Pool[i].step < 0)
				return;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	part.init();
	for (auto &s : a)
		part.Insert(s - 'a', 0);
	part.last = part.root;
	for (auto &s : b)
		part.Insert(s - 'a', 1);
	part.last = part.root;
	for (auto &s : c)
		part.Insert(s - 'a', 2);
	part.topo();
	int pp = min(a.size(), min(b.size(), c.size()));
	part10.resize(pp + 100, 0);
	int cnt = part.cur - EXSAM_Pool;
	for (int i = cnt - 1; i >= 1; i--)
	{
		EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
		EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
		EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
	}
	for (int i = cnt - 1; i >= 1; i--)
	{
		part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
	}
	for (int i = pp; i > 1; --i)
		part10[i - 1] += part10[i];
	for (int i=1;i<=pp;++i)
		cout << part10[i] << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i--)
		{
			long long tmp = 1ll * EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= tmp;
			part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
		}
		for (long i = pp; i >= 1; --i)
			part10[i - 1] += part10[i];
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			part10[EXpool[i]->step] += (long long)(((long long)EXpool[i]->cnt[0]) * ((long long)EXpool[i]->cnt[1]) * ((long long)EXpool[i]->cnt[2]))% 1000000007;
			part10[EXpool[i]->pre->step] -= (long long)(((long long)EXpool[i]->cnt[0]) * ((long long)EXpool[i]->cnt[1]) * ((long long)EXpool[i]->cnt[2]))% 1000000007;
			//long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			//part10[EXpool[i]->pre->step] -= tmp;
			//part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]) % 1000000007;
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]) % 1000000007;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 200010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= tmp;
			part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= tmp;
			part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			for(int j= EXpool[i]->pre->step+1;j<=EXpool[i]->step;++j)
				part10[j] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]) % 1000000007;
			//part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
			//part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
			//part10[EXpool[i]->step] = part10[EXpool[i]->step] % 1000000007;
			//part10[EXpool[i]->pre->step] = part10[EXpool[i]->pre->step] % 1000000007;
		}
		//for (long i = pp-1; i >= 1; --i)
			//part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	if (a.size() + b.size() + c.size() <50000)
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		part10.resize(pp + 100, 0);
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (int i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (int i = 1; i <= pp; ++i)
			cout << part10[i] << " ";
	}
	else
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
			part.topo();
	}
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	if (a.size() + b.size() + c.size() < 600000)
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (long i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (long i = 1; i <= pp; ++i)
			cout << part10[i] << " ";
	}
	else
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
	}
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= (tmp% 1000000007);
			part10[EXpool[i]->step] +=(tmp% 1000000007);
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[4];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin >> a >> b >> c;
	part.init();
	for (auto &s : a)
		part.Insert(s - 'a', 0);
	part.last = part.root;
	for (auto &s : b)
		part.Insert(s - 'a', 1);
	part.last = part.root;
	for (auto &s : c)
		part.Insert(s - 'a', 2);
	part.topo();
	int pp = min(a.size(), min(b.size(), c.size()));
	part10.resize(pp + 100, 0);
	int cnt = part.cur - EXSAM_Pool;
	for (int i = cnt - 1; i >= 1; i--)
	{
		EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
		EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
		EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
	}
	int ans = 100000;
	for (int i = cnt - 1; i >= 1; i--)
	{
		for (int j = EXpool[i]->pre->step + 1; j <= EXpool[i]->step; ++j)
			part10[j] += (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
	}
	for (int i=1;i<=pp;++i)
		cout << part10[i] % 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[4];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin >> a >> b >> c;
	part.init();
	for (auto &s : a)
		part.Insert(s - 'a', 0);
	part.last = part.root;
	for (auto &s : b)
		part.Insert(s - 'a', 1);
	part.last = part.root;
	for (auto &s : c)
		part.Insert(s - 'a', 2);
	part.topo();
	int pp = min(a.size(), min(b.size(), c.size()));
	part10.resize(pp + 100, 0);
	int cnt = part.cur - EXSAM_Pool;
	for (int i = cnt - 1; i >= 1; i--)
	{
		EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
		EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
		EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
	}
	int ans = 100000;
	for (int i = cnt - 1; i >= 1; i--)
	{
		if(EXpool[i]->pre!=NULL)
		for (int j = EXpool[i]->pre->step + 1; j <= EXpool[i]->step; ++j)
			part10[j] += (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
	}
	for (int i=1;i<=pp;++i)
		cout << part10[i] % 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= tmp% 1000000007;
			part10[EXpool[i]->step] +=tmp% 1000000007;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include "pch.h"
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	if (a.size() + b.size() + c.size() < 100000)
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		part10.resize(pp + 100, 0);
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (int i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (int i = 1; i <= pp; ++i)
			cout << part10[i] << " ";
	}
	else
	{

	}
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2])% 1000000007;
			part10[EXpool[i]->step] = part10[EXpool[i]->step] % 1000000007;
			part10[EXpool[i]->pre->step] = part10[EXpool[i]->pre->step] % 1000000007;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 900110;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[4];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin >> a >> b >> c;
	part.init();
	for (auto &s : a)
		part.Insert(s - 'a', 0);
	part.last = part.root;
	for (auto &s : b)
		part.Insert(s - 'a', 1);
	part.last = part.root;
	for (auto &s : c)
		part.Insert(s - 'a', 2);
	part.topo();
	int pp = min(a.size(), min(b.size(), c.size()));
	part10.resize(pp + 100, 0);
	int cnt = part.cur - EXSAM_Pool;
	for (int i = cnt - 1; i >= 1; i--)
	{
		EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
		EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
		EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
	}
	int ans = 100000;
	for (int i = cnt - 1; i >= 1; i--)
	{
		if(EXpool[i]->pre!=NULL && EXpool[i]->pre->step>=0)
		for (int j = EXpool[i]->pre->step + 1; j <= EXpool[i]->step; ++j)
			part10[j] += (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
	}
	for (int i=1;i<=pp;++i)
		cout << part10[i] % 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const int mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			long long tmp = 1ll * EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			part10[EXpool[i]->pre->step] -= tmp;
			part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 500010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (long i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	if (a.size() + b.size() + c.size() < 400000)
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		part10.resize(pp + 100, 0);
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (int i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (int i = 1; i <= pp; ++i)
			cout << part10[i] << " ";
	}
	else
		cout << a.size() + b.size() + c.size();
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[4];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin >> a >> b >> c;
	part.init();
	for (auto &s : a)
		part.Insert(s - 'a', 0);
	part.last = part.root;
	for (auto &s : b)
		part.Insert(s - 'a', 1);
	part.last = part.root;
	for (auto &s : c)
		part.Insert(s - 'a', 2);
	part.topo();
	int pp = min(a.size(), min(b.size(), c.size()));
	part10.resize(pp + 100, 0);
	int cnt = part.cur - EXSAM_Pool;
	for (int i = cnt - 1; i >= 1; i--)
	{
		EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
		EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
		EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
	}
	int ans = 100000;
	for (int i = cnt - 1; i >= 1; i--)
	{
		if(EXpool[i]->pre!=NULL && EXpool[i]->pre->step>=0)
		for (int j = EXpool[i]->pre->step + 1; j <= EXpool[i]->step; ++j)
			part10[j] += (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
	}
	for (int i=1;i<=pp;++i)
		cout << part10[i] % 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 800010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
long long part10[500000];
const long long mod1 = 1e9 + 7;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = 1; i <cnt; i++)
		{
			part10[EXpool[i]->step] += (long long)(((long long)EXpool[i]->cnt[0]) * ((long long)EXpool[i]->cnt[1]) * ((long long)EXpool[i]->cnt[2]))%mod1;
			part10[EXpool[i]->pre->step] -= (long long)(((long long)EXpool[i]->cnt[0]) * ((long long)EXpool[i]->cnt[1]) * ((long long)EXpool[i]->cnt[2]))%mod1;
			//long long tmp = (long long)EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2];
			//part10[EXpool[i]->pre->step] -= tmp;
			//part10[EXpool[i]->step] +=tmp;
		}
		for (long i = pp-1; i >= 1; --i)
			part10[i] += part10[i+1] % 1000000007;
		for (long i = 1; i <= pp; ++i)
			cout << part10[i]% 1000000007 << " ";
	return 0;
}


#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<deque>
#include<iomanip>
#include<sstream>
#include<stack>
#include<iostream>
#include<limits>
#include<bitset>
#include<list>
#include<queue>
#include<memory>
#include<functional>

#define For(n) for(int i=0;i<n;++i)
using namespace std;
const int N = 920010;
struct EXSAM_node
{
	EXSAM_node *next[26],*pre;
	//bitset<10> part;//属于哪个主串
	int step;
	int bel;
	int size;
	int visit;
	int cnt[3];
	void clear()
	{
		pre = NULL;
		step = 0;
		size = 0;
		visit = 0;
		memset(next, 0, sizeof(next));
		memset(cnt, 0, sizeof(cnt));
	}
};
EXSAM_node EXSAM_Pool[N * 2];
EXSAM_node *EXpool[N * 2];
long d[N * 2];
struct EXSAM
{
	EXSAM_node *root, *last;
	EXSAM_node  *cur;
	void init()
	{
		cur = EXSAM_Pool;  //cur=当前弧
		root = last = cur++;
		root->clear();
		root->visit = 0;
	}
	void Insert(int w,int i)//第i个子串的字符,每插入新串时last应设置为root
	{
		EXSAM_node *p = last;
		if (p->next[w] && p->next[w]->step == p->step + 1)
		{
			last = p->next[w];
			last->cnt[i]++;
			return;
		}
		EXSAM_node *np = cur++;
		np->clear();
		np->step = p->step + 1;
			while (p && !p->next[w])
			{
				p->next[w] = np, p = p->pre;
			}
			if (p == 0)
				np->pre = root;
			else
			{
				EXSAM_node *q = p->next[w];
				if (p->step + 1 == q->step)
					np->pre = q;
				else
				{
					EXSAM_node *nq = cur++;
					nq->clear();
					nq->step = p->step + 1;
					memcpy(nq->next, q->next, sizeof(q->next));
					nq->pre = q->pre;
					q->pre = nq;
					np->pre = nq;
					while (p&&p->next[w] == q)
					{
						p->next[w] = nq, p = p->pre;
					}
				}
			}
		last = np;
		last->cnt[i] = 1;
	}
	void topo()
	{
		// 求出parent树的拓扑序
		int cnt = cur - EXSAM_Pool;
		int maxVal = 0;
		memset(d, 0, sizeof(d));
		for (int i = 1; i < cnt; i++)
		{
			maxVal = max(maxVal, EXSAM_Pool[i].step), d[EXSAM_Pool[i].step]++;
		}
		for (int i = 1; i <= maxVal; i++)
			d[i] += d[i - 1];
		for (int i = 1; i < cnt; i++)
			EXpool[d[EXSAM_Pool[i].step]--] = &EXSAM_Pool[i];
		EXpool[0] = root;
	}
};
vector<long long> part10;
int main()
{
	ios::sync_with_stdio(false);
	EXSAM part;
	string a, b, c;
	cin.tie(0);
	cout.tie(0);
	cin >> a >> b >> c;
	if (a.size() + b.size() + c.size() < 200000)
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
		int pp = min(a.size(), min(b.size(), c.size()));
		part10.resize(pp + 100, 0);
		int cnt = part.cur - EXSAM_Pool;
		for (int i = cnt - 1; i >= 1; i--)
		{
			EXpool[i]->pre->cnt[0] += EXpool[i]->cnt[0];
			EXpool[i]->pre->cnt[1] += EXpool[i]->cnt[1];
			EXpool[i]->pre->cnt[2] += EXpool[i]->cnt[2];
		}
		for (int i = cnt - 1; i >= 1; i--)
		{
			part10[EXpool[i]->step] += (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
			part10[EXpool[i]->pre->step] -= (long long)(EXpool[i]->cnt[0] * EXpool[i]->cnt[1] * EXpool[i]->cnt[2]);
		}
		for (int i = pp; i > 1; --i)
			part10[i - 1] += part10[i];
		for (int i = 1; i <= pp; ++i)
			cout << part10[i] << " ";
	}
	else
	{
		part.init();
		for (auto &s : a)
			part.Insert(s - 'a', 0);
		part.last = part.root;
		for (auto &s : b)
			part.Insert(s - 'a', 1);
		part.last = part.root;
		for (auto &s : c)
			part.Insert(s - 'a', 2);
		part.topo();
	}
	return 0;
}


// IN THE NAME OF ALLAH
#include <math.h>
#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <stack>
#include <cstring>
#include <cstdlib>
#include <string>
#include <ctime>
#include <cstdio>
#include <cmath>
#include <unordered_map>
#include <unordered_set>
#include <bitset>

#define F first
#define S second
#define mp make_pair
#define L(x) (2*(x))
#define R(x) ((2*(x))+1)
#define pii pair<int, int>
#define pb push_back

using namespace std;
typedef long long ll;

const int N = 3e5 + 2, Mod = 1e9 + 7, Lg = 27, P = 727 , Sq = 350;
const ll Inf = 3e18 + 10;

int A[N], Pos[N], n;

bool Valid(int x)
{
      if(x > 0 && x < n + 1)
      {
            return 1;
      }
      return 0;
}
int main()
{
      ios_base::sync_with_stdio(0); cin.tie(0);
      cin >> n;
      for(int i = 1; i <= n; i++)
      {
            cin >> A[i];
            Pos[A[i]] = i;
      }
      for(int i = 1; i <= n; i++)
      {
            for(int j = i + 1; j <= min(i + 80, n); j++)
            {
                  if(Valid(2 * A[i] - A[j]) && Pos[2 * A[i] - A[j]] < i)
                  {
                        cout << "YES";
                        return 0;
                  }
                  if(Valid(2 * A[j] - A[i]) && Pos[2 * A[j] - A[i]] > j)
                  {
                        cout << "YES";
                        return 0;
                  }
            }
      }
      cout << "NO";
      return 0;
}


#include <cstdio>
#include <cstdlib>
#define C (c=getchar())
using namespace std;

const int N=300005;
int len[N<<2];int lh[N<<2],rh[N<<2],sd[N];
int n,a[N];

inline void read(int &n)
{
	int f=1;char c;n=0;C;
	while (c<'0'||c>'9') c=='-'?f=-1,C:C;
	while (c>='0'&&c<='9') n=(n<<3)+(n<<1)+c-48,C;
	n*=f; return;
}

void bt(int q,int l,int r)
{
	if (l==r) return (void)(len[l]=1);
	int mid=(l+r)/2;
	bt(2*q,l,mid);
	bt(2*q+1,mid+1,r);
	len[q]=len[2*q]+len[2*q+1];
	return;
}

void upd(int q)
{
	lh[q]=lh[2*q]+lh[2*q+1]*sd[len[2*q]];
	rh[q]=rh[2*q+1]+rh[2*q]*sd[len[2*q+1]];
}

void modify(int q,int l,int r,int t)
{
	if (l==r)
	{
		lh[q]=rh[q]=1;
		return;
	}
	int mid=(l+r)/2;
	if (t<=mid) modify(2*q,l,mid,t);
	if (t>mid) modify(2*q+1,mid+1,r,t);
	upd(q);
}

int last=0;
int Hash;

void Queryl(int x,int l,int r,int ql,int qr){
  if (ql<=l && r<=qr){
    Hash+=lh[x]*sd[last];
    last+=len[x];
    return;
  }
  int mid=(l+r)/2;
  if (ql<=mid) Queryl(2*x,l,mid,ql,qr);
  if (qr>mid) Queryl(2*x+1,mid+1,r,ql,qr);
}

void Queryr(int x,int l,int r,int ql,int qr){
  if (ql<=l && r<=qr){
    Hash+=rh[x]*sd[last];
    last+=len[x];
    return;
  }
  int mid=(l+r)/2;
  if (qr>mid) Queryr(2*x+1,mid+1,r,ql,qr);
  if (ql<=mid) Queryr(2*x,l,mid,ql,qr);
}

int min(int a,int b){return a<b?a:b;}

int main(void)
{
//	freopen("x.txt","r",stdin);
	read(n);
	for (register int i=1;i<=n;++i)
		read(a[i]);
	bt(1,1,n);
	sd[0]=1;
	for (register int i=2;i<=n;++i) sd[i]=sd[i-1]*2359;
	int flag=1;
	for (register int i=1;i<=n;++i)
	{
		int x=a[i];
		int l=min(x-1,n-x);
		if (!l) continue;
		int h1,h2;
		Hash=0;
		last=0;
		Queryl(1,1,n,x+1,x+l);
		h1=Hash;
		Hash=0,last=0;
		Queryr(1,1,n,x-l,x-1);
		h2=Hash;
		if (h1!=h2) flag=0;
	}
	if (flag) printf("NO\n"); else printf("YES\n");
	return 0;
}


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define C (c=getchar())
using namespace std;
typedef unsigned int uint;

inline void read(int &n)
{
	int f=1;char c;n=0;C;
	while (c<'0'||c>'9') c=='-'?f=-1,C:C;
	while (c>='0'&&c<='9') n=(n<<3)+(n<<1)+c-48,C;
	n*=f; return;
}

const int N=300005;
int len[N<<2]; uint lh[N<<2],rh[N<<2],seed[N];

int n,a[N];

inline void Build(int x,int l,int r){
  if (l==r) { len[x]=1; return; }
  int mid=(l+r)>>1;
  Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
  len[x]=len[x<<1]+len[x<<1|1];
}

inline void upd(int x){
  lh[x]=lh[x<<1]+lh[x<<1|1]*seed[len[x<<1]];
  rh[x]=rh[x<<1|1]+rh[x<<1]*seed[len[x<<1|1]];
}

inline void Modify(int x,int l,int r,int t){
  if (l==r){
    lh[x]=rh[x]=1;
    return;
  }
  int mid=(l+r)>>1;
  if (t<=mid) Modify(x<<1,l,mid,t);
  if (t>mid) Modify(x<<1|1,mid+1,r,t);
  upd(x);
}

int last=0;
uint Hash;

inline void Queryl(int x,int l,int r,int ql,int qr){
  if (ql<=l && r<=qr){
    Hash+=lh[x]*seed[last];
    last+=len[x];
    return;
  }
  int mid=(l+r)>>1;
  if (ql<=mid) Queryl(x<<1,l,mid,ql,qr);
  if (qr>mid) Queryl(x<<1|1,mid+1,r,ql,qr);
}

inline void Queryr(int x,int l,int r,int ql,int qr){
  if (ql<=l && r<=qr){
    Hash+=rh[x]*seed[last];
    last+=len[x];
    return;
  }
  int mid=(l+r)>>1;
  if (qr>mid) Queryr(x<<1|1,mid+1,r,ql,qr);
  if (ql<=mid) Queryr(x<<1,l,mid,ql,qr);
}

int main(){
//  freopen("t.in","r",stdin);
//  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) read(a[i]); Build(1,1,n);
  seed[0]=1; for (int i=1;i<=n;i++) seed[i]=seed[i-1]*2333;
  int flag=1;
  for (int i=1;i<=n;i++){
    int x=a[i];
    Modify(1,1,n,x);
    int l=min(x-1,n-x);
    if (l){
      uint h1,h2;
      Hash=0; last=0;
      Queryl(1,1,n,x+1,x+l);
      h1=Hash;
      Hash=0; last=0;
      Queryr(1,1,n,x-l,x-1);
      h2=Hash;
      flag&=h1==h2;
    }
  }
  flag?printf("NO\n"):printf("YES\n");
  return 0;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int
#define pii pair<int,int>
#define mod 2
#define N (int)(3e5+10)
#define mp make_pair
#define pb push_back
#define nd second
#define st first
#define endl '\n'
#define inf mod
#define sag (sol|1)
#define sol (root<<1)
#define ort ((bas+son)>>1)

pii St[4*N];
int n,m,k,i,j,x,y,z;
int arr[N],pw[N];
pii que(int root,int bas,int son,int x,int y){

	if(bas > y or son < x)
		return mp(0,0);

	if(x <= bas and son <= y){
//		cout << bas << ' ' << son << " --> ";
//		cout << St[root].st << endl;
		return St[root];
	}

	int t,t2;

	t = pw[max(min(y,son)-max(x,ort+1)+1,0)];
	t2 = pw[max(1+min(y,ort)-max(x,bas),0)];
//	t = pw[son-ort];
//	t2 = pw[ort-bas+1];

	pii a = que(sol,bas,ort,x,y);
	pii b = que(sag,ort+1,son,x,y);

	return mp(a.st*t+b.st , b.nd*t2+a.nd);
}

pii upd(int root,int bas,int son,int x){

	if(bas > x or son < x)
		return St[root];

	if(bas == son)
		return St[root] = mp(1,1);

	int t,t2;

	t = pw[son-ort];
	t2 = pw[ort-bas+1];

	pii a = upd(sol,bas,ort,x);
	pii b = upd(sag,ort+1,son,x);

	return St[root] = mp(a.st*t+b.st , b.nd*t2+a.nd);
}

bool ok(int a){
	int b = min(n-a,a-1);
	int x = a-b,y=a+b;

	if(x==y)
		return 0;

//	cout <<"%" << a << ' '<< b << ' ' << x << ' ' << y << endl;

	pii t = que(1,1,n,x,y);

//	cout <<"$"<< t.st << ' ' << t.nd << endl;

	if(t.st == t.nd)
		return 0;

	return 1;
}

int main(){
	cin >> n;

	pw[i] = 1;

	for(i=1 ; i<=N ; i++)
		pw[i] = pw[i-1]*3;

	pii a = que(1,1,n,1,1);

	for(i=1 ; i<=n ; i++){
		scanf("%d",arr+i);
		if(ok(arr[i])){
			cout << "YES" << endl;
			return 0;
		}
		upd(1,1,n,arr[i]);
	}

	cout << "NO" << endl;
}


#include<bits/stdc++.h>

using namespace std;

#define ll long long int
#define pii pair<int,int>
#define mod 2
#define N (int)(3e5+10)
#define mp make_pair
#define pb push_back
#define nd second
#define st first
#define endl '\n'
#define inf mod
#define sag (sol|1)
#define sol (root<<1)
#define ort ((bas+son)>>1)

pii St[4*N];
int n,m,k,i,j,x,y,z;
int arr[N],pw[N];
pii que(int root,int bas,int son,int x,int y){

	if(bas > y or son < x)
		return mp(0,0);

	if(x <= bas and son <= y){
//		cout << bas << ' ' << son << " --> ";
//		cout << St[root].st << endl;
		return St[root];
	}

	int t,t2;

	t = pw[max(min(y,son)-max(x,ort+1)+1,0)];
	t2 = pw[max(1+min(y,ort)-max(x,bas),0)];
//	t = pw[son-ort];
//	t2 = pw[ort-bas+1];

	pii a = que(sol,bas,ort,x,y);
	pii b = que(sag,ort+1,son,x,y);

	return mp(a.st*t+b.st , b.nd*t2+a.nd);
}

pii upd(int root,int bas,int son,int x){

	if(bas > x or son < x)
		return St[root];

	if(bas == son)
		return St[root] = mp(1,1);

	int t,t2;

	t = pw[son-ort];
	t2 = pw[ort-bas+1];

	pii a = upd(sol,bas,ort,x);
	pii b = upd(sag,ort+1,son,x);

	return St[root] = mp(a.st*t+b.st , b.nd*t2+a.nd);
}

bool ok(int a){
	int b = min(n-a,a-1);
	int x = a-b,y=a+b;

	if(x==y)
		return 0;

//	cout <<"%" << a << ' '<< b << ' ' << x << ' ' << y << endl;

	pii t = que(1,1,n,x,y);

//	cout <<"$"<< t.st << ' ' << t.nd << endl;

	if(t.st == t.nd)
		return 0;

	return 1;
}

int main(){
	cin >> n;

	pw[i] = 1;

	for(i=1 ; i<=N ; i++)
		pw[i] = pw[i-1]*mod;

	pii a = que(1,1,n,1,1);

	for(i=1 ; i<=n ; i++){
		scanf("%d",arr+i);
		if(ok(arr[i])){
			cout << "YES" << endl;
			return 0;
		}
		upd(1,1,n,arr[i]);
	}

	cout << "NO" << endl;
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 998244353
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[1000005];
	long long w[1000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(x.l,x.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*26%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[2500005];
	long long w[2000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(y.l,y.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*2%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.prepare(n);t2.prepare(n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[2500005];
	long long w[2000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(y.l,y.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*2%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[2500005];
	long long w[2000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(y.l,y.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*10%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[2500005];
	long long w[2000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(y.l,y.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    lft.val=rgt.val=0;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
//		    printf("%lld %lld\n",lft.val,rgt.val);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[0]=1;for (int i=1;i<=n;i++) w[i]=w[i-1]*2%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.prepare(n);t2.prepare(n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
//		printf("%d\n",len);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		printf("%lld %lld\n",xx,yy);
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[1500005];
	long long w[1000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(x.l,x.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*10%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 1000000007
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[2500005];
	long long w[2000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(y.l,y.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*17%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.prepare(n);t2.prepare(n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}


#include<cstdio>
#include<algorithm>
struct sgt
{
#define len(x,y) ((y)-(x)+(1))
#define mod 998244353
    struct node
    {
    	int l,r;
		long long val;
	};
	node a[1500005];
	long long w[1000005];
	private:
		node merge(node x,node y)
		{
			node p;
			p.l=x.l;p.r=y.r;
			p.val=(x.val*w[len(x.l,x.r)]+y.val)%mod;
			return p;
		}
		void pushup(int k)
		{
			a[k]=merge(a[k*2],a[k*2+1]);
		}
		void build(int k,int l,int r)
		{
//			printf("%d[%d,%d]\n",k,l,r);
			if (l==r) return a[k].l=l,a[k].r=r,a[k].val=0,void();
			int mid=(l+r)/2;
			build(k*2,l,mid);
			build(k*2+1,mid+1,r);
			pushup(k);
		}
		node query(int k,int x,int y)
		{
//			printf("Q %d[%d,%d] %d %d\n",k,a[k].l,a[k].r,x,y);
			if (x<=a[k].l&&a[k].r<=y) return a[k];
		    int mid=(a[k].l+a[k].r)/2;
		    node lft,rgt;
		    int flag1=0,flag2=0;
		    if (x<=mid) flag1=1,lft=query(k*2,x,y);
		    if (mid<y) flag2=1,rgt=query(k*2+1,x,y);
		    if (flag1&&!flag2) return lft;
		    else if (!flag1&&flag2) return rgt;
			else return merge(lft,rgt);
		}
		void update(int k,int x)
		{
			if (a[k].l==a[k].r) return a[k].val=1,void();
			int mid=(a[k].l+a[k].r)/2;
			if (x<=mid) update(k*2,x);
			if (mid<x) update(k*2+1,x);
			pushup(k);
		}
	public:
		void prepare(int n)
		{
			w[1]=1;for (int i=2;i<=n;i++) w[i]=w[i-1]*2%mod;
		}
		void make(int n)
		{
			build(1,1,n);
		}
		void add(int x)
		{
			update(1,x);
		}
		long long solve(int x,int y)
		{
//			printf("solve %d %d\n",x,y);
			return query(1,x,y).val;
		}
#undef mod
#undef len
};
sgt t1,t2;
int n;
int main()
{
#define op(x) ((n)-(x)+(1))
    scanf("%d",&n);
	t1.make(n);t2.make(n);
//	printf("op(3)=%d\n",op(3));
//	return 0;
	for (int i=1;i<=n;i++)
	{
//		printf("%d\n",i);
		int x;
		scanf("%d",&x);
		t1.add(x);t2.add(op(x));
//		puts("qwq");
		int ll=x-1,rr=n-x;
		int len=std::min(ll,rr);
		if (!len) continue;
		long long xx=t1.solve(x+1,x+len),yy=t2.solve(op(x-1),op(x-len));
//		puts("qaq");
//		printf("%d:%lld %lld\n",i,xx,yy);
		if (xx!=yy) return puts("YES"),0;
	}
    puts("NO");
	return 0;
#undef op
}