#ifndef __ROLLING_HASH_H__
#define __ROLLING_HASH_H__

/* updated: 2020-08-10 */

#include <array>
#include <string>
#include <vector>

/* 
// ローリングハッシュ計算用の各種定数
// 配列 a[0, n) に対して sum [i = 0 to n - 1] (a[i] * x^i) mod m の形でハッシュを計算する
// radix は計算に用いる x で, その逆元が inv である
*/
class RollingHashConstant {
public:
	static constexpr int trials = 3;	// 用いる mod の数
	
	// TODO: 良い定義方法を考える
	// mod は 2 ^ 31 以下の素数
	static constexpr std::array<uint32_t, trials> mod_list = {
		1029392827,
		1052308451,
		1038234577
	};
	static constexpr std::array<uint32_t, trials> radix_list = {
		922013041,
		225237713,
		867506933
	};
	static constexpr std::array<uint32_t, trials> inv_list = {
		182811337,
		394845847,
		601827159
	};
};

/*
// ローリングハッシュの計算を補助する型 (複数要素の演算をまとめて行うクラス: 1つの整数と考えてもよい)
// これをハッシュとして使うと長さの異なる文字列で衝突するので注意
// 比較関数は set/map 用
*/
class RollingHashBase {
	static constexpr int trials_m = RollingHashConstant::trials;
	std::array<uint32_t, trials_m> values_m = {};

public:
	RollingHashBase() = default;
	explicit RollingHashBase(uint32_t value);

private:
	explicit RollingHashBase(const std::array<uint32_t, trials_m>& values);

public:
	static int compare(const RollingHashBase& a, const RollingHashBase& b);
	static RollingHashBase getRadix();
	static RollingHashBase getInverseRadix();

	RollingHashBase& operator+=(const RollingHashBase& other);
	RollingHashBase& operator-=(const RollingHashBase& other);
	RollingHashBase& operator*=(const RollingHashBase& other);
};

bool operator==(const RollingHashBase& a, const RollingHashBase& b);
bool operator!=(const RollingHashBase& a, const RollingHashBase& b);
bool operator<(const RollingHashBase& a, const RollingHashBase& b);
bool operator<=(const RollingHashBase& a, const RollingHashBase& b);
bool operator>(const RollingHashBase& a, const RollingHashBase& b);
bool operator>=(const RollingHashBase& a, const RollingHashBase& b);

RollingHashBase operator+(const RollingHashBase& a, const RollingHashBase& b);
RollingHashBase operator-(const RollingHashBase& a, const RollingHashBase& b);
RollingHashBase operator*(const RollingHashBase& a, const RollingHashBase& b);

/* radix の累乗を O(1) で得るためにメモを行うクラス */
class RollingHashMemo {
	static std::vector<RollingHashBase> pow_table_m;	// radix の累乗
	static std::vector<RollingHashBase> inv_table_m;	// radix の逆元の累乗

public:
	static void prepare(int new_size);
	static RollingHashBase getPower(int exp);
	static RollingHashBase getInversePower(int exp);
};

/* 
// RollingHashBase に文字列長の情報を付加したもの
// ある文字列に(ほぼ一意に)対応すると考えてよい: 関数の命名もこれにならう
// 比較関数は set/map 用
*/
class RollingHash {
	int length_m = 0;
	RollingHashBase base_m;

public:
	RollingHash() = default;
	explicit RollingHash(int length, const RollingHashBase& base);
	explicit RollingHash(uint32_t value);

	void pushFront(uint32_t element);
	void pushBack(uint32_t element);
	void popFront(uint32_t element);
	void popBack(uint32_t element);

	static int compare(const RollingHash& a, const RollingHash& b);
	static RollingHash concatenate(const RollingHash& a, const RollingHash& b);
	static RollingHash removePrefix(const RollingHash& a, const RollingHash& b);
	static RollingHash removeSuffix(const RollingHash& a, const RollingHash& b);
};

bool operator==(const RollingHash& a, const RollingHash& b);
bool operator!=(const RollingHash& a, const RollingHash& b);
bool operator<(const RollingHash& a, const RollingHash& b);
bool operator<=(const RollingHash& a, const RollingHash& b);
bool operator>(const RollingHash& a, const RollingHash& b);
bool operator>=(const RollingHash& a, const RollingHash& b);

/* 
// 任意の部分文字列のハッシュを O(1) で得られる文字列クラス (前計算 O(n))
// 文字列を引数にインスタンスを構築し substr で部分文字列のハッシュを得る
*/
class RollingHashString {
	int length_m = 0;					// 保持している文字列の長さ
	std::vector<RollingHash> hashes_m;	// hashes[i] = 部分文字列 [0, i) の hash (hashes.size () == length + 1) 

public:
	RollingHashString();
	explicit RollingHashString(const std::vector<uint32_t>& str);
	explicit RollingHashString(const std::string& str);

private:
	void initialize(const std::vector<uint32_t>& str);

public:
	RollingHash substr(int index, int count = -1);
};

#endif

#ifdef ONLY_MY_ENVIR
#include "RollingHash.h"
#endif

/*-----------------------------------*/
/*-------   RollingHashBase   -------*/
/*-----------------------------------*/

RollingHashBase::RollingHashBase(uint32_t value) {
	for (int i = 0; i < trials_m; ++i) {
		values_m[i] = value % RollingHashConstant::mod_list[i];
	}
}

RollingHashBase::RollingHashBase(const std::array<uint32_t, trials_m>& values) 
	: values_m(values) {
}

int RollingHashBase::compare(const RollingHashBase& a, const RollingHashBase& b) {
	for (int i = 0; i < trials_m; ++i) {
		if (a.values_m[i] < b.values_m[i]) return -1;
		if (a.values_m[i] > b.values_m[i]) return 1;
	}
	return 0;
}

RollingHashBase RollingHashBase::getRadix() {
	return RollingHashBase(RollingHashConstant::radix_list);
}

RollingHashBase RollingHashBase::getInverseRadix() {
	return RollingHashBase(RollingHashConstant::inv_list);
}

RollingHashBase& RollingHashBase::operator+=(const RollingHashBase& other) {
	for (int i = 0; i < trials_m; ++i) {
		values_m[i] += other.values_m[i];
		if (values_m[i] >= RollingHashConstant::mod_list[i]) {
			values_m[i] -= RollingHashConstant::mod_list[i];
		}
	}
	return *this;
}

RollingHashBase& RollingHashBase::operator-=(const RollingHashBase& other) {
	for (int i = 0; i < trials_m; ++i) {
		if (values_m[i] < other.values_m[i]) {
			values_m[i] += RollingHashConstant::mod_list[i];
		}
		values_m[i] -= other.values_m[i];
	}
	return *this;
}

RollingHashBase& RollingHashBase::operator*=(const RollingHashBase& other) {
	for (int i = 0; i < trials_m; ++i) {
		values_m[i] = uint64_t(values_m[i]) * other.values_m[i] % RollingHashConstant::mod_list[i];
	}
	return *this;
}

bool operator==(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) == 0;
}

bool operator!=(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) != 0;
}

bool operator<(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) < 0;
}

bool operator<=(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) <= 0;
}

bool operator>(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) > 0;
}

bool operator>=(const RollingHashBase& a, const RollingHashBase& b) {
	return RollingHashBase::compare(a, b) >= 0;
}

RollingHashBase operator+(const RollingHashBase& a, const RollingHashBase& b) {
	RollingHashBase ret(a);
	ret += b;
	return ret;
}

RollingHashBase operator-(const RollingHashBase& a, const RollingHashBase& b) {
	RollingHashBase ret(a);
	ret -= b;
	return ret;
}

RollingHashBase operator*(const RollingHashBase& a, const RollingHashBase& b) {
	RollingHashBase ret(a);
	ret *= b;
	return ret;
}

/*-----------------------------------*/
/*-------   RollingHashMemo   -------*/
/*-----------------------------------*/

// 単位元を入れておく
std::vector<RollingHashBase> RollingHashMemo::pow_table_m(1, RollingHashBase(1));
std::vector<RollingHashBase> RollingHashMemo::inv_table_m(1, RollingHashBase(1));

/* 長さ new_size まで累乗を前計算する O(new_size - old_size) */
void RollingHashMemo::prepare(int new_size) {
	int old_size = pow_table_m.size();
	if (old_size >= new_size) return;
	pow_table_m.resize(new_size);
	inv_table_m.resize(new_size);

	for (int i = old_size; i < new_size; ++i) {
		pow_table_m[i] = RollingHashBase::getRadix() * pow_table_m[i - 1];
		inv_table_m[i] = RollingHashBase::getInverseRadix() * inv_table_m[i - 1];
	}
}

/* radix の exp 乗を得る O(1) */
RollingHashBase RollingHashMemo::getPower(int exp) {
	prepare(exp + 1);
	return pow_table_m[exp];
}

/* radix の -exp 乗を得る O(1) */
RollingHashBase RollingHashMemo::getInversePower(int exp) {
	prepare(exp + 1);
	return inv_table_m[exp];
}

/*-----------------------------------*/
/*---------   RollingHash   ---------*/
/*-----------------------------------*/

RollingHash::RollingHash(int length, const RollingHashBase& base)
	: length_m(length), base_m(base) {
}

RollingHash::RollingHash(uint32_t value) 
	: length_m(1), base_m(value) {
}

/* 文字列先頭への追加 O(1) */
void RollingHash::pushFront(uint32_t element) {
	*this = concatenate(RollingHash(element), *this);
}

/* 文字列末尾への追加 O(1) */
void RollingHash::pushBack(uint32_t element) {
	*this = concatenate(*this, RollingHash(element));
}

/* 先頭要素の消去 O(1) */
/* 先頭要素が element 以外であった場合は正しい結果にならない */
void RollingHash::popFront(uint32_t element) {
	*this = removePrefix(RollingHash(element), *this);
}

/* 末尾要素の消去 O(1) */
/* 末尾要素が element 以外であった場合は正しい結果にならない */
void RollingHash::popBack(uint32_t element) {
	*this = removeSuffix(*this, RollingHash(element));
}

int RollingHash::compare(const RollingHash& a, const RollingHash& b) {
	if (a.length_m < b.length_m) return -1;
	if (a.length_m > b.length_m) return 1;
	return RollingHashBase::compare(a.base_m, b.base_m);
}

/* 文字列の連結 O(1) */
RollingHash RollingHash::concatenate(const RollingHash& a, const RollingHash& b) {
	return RollingHash(
		a.length_m + b.length_m,
		a.base_m + RollingHashMemo::getPower(a.length_m) * b.base_m
	);
}

/* 文字列 a から接頭辞 b を取り除いた結果を返す O(1) */
/* 文字列 b が文字列 a の接頭辞でない場合は正しい結果にならない */
RollingHash RollingHash::removePrefix(const RollingHash& a, const RollingHash& b) {
	return RollingHash(
		a.length_m - b.length_m,
		RollingHashMemo::getInversePower(a.length_m) * (a.base_m - b.base_m)
	);
}

/* 文字列 a から接尾辞 b を取り除いた結果を返す O(1) */
/* 文字列 b が文字列 a の接尾辞でない場合は正しい結果にならない */
RollingHash RollingHash::removeSuffix(const RollingHash& a, const RollingHash& b) {
	return RollingHash(
		a.length_m - b.length_m,
		a.base_m - RollingHashMemo::getPower(a.length_m) * b.base_m
	);
}

bool operator==(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) == 0;
}

bool operator!=(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) != 0;
}

bool operator<(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) < 0;
}

bool operator<=(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) <= 0;
}

bool operator>(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) > 0;
}

bool operator>=(const RollingHash& a, const RollingHash& b) {
	return RollingHash::compare(a, b) >= 0;
}

/*-----------------------------------*/
/*------   RollingHashString   ------*/
/*-----------------------------------*/

/* 空文字列を生成 */
RollingHashString::RollingHashString() {
	initialize(std::vector<uint32_t>());
}

RollingHashString::RollingHashString(const std::vector<uint32_t>& str) {
	initialize(str);
}

RollingHashString::RollingHashString(const std::string& str) {
	initialize(std::vector<uint32_t>(str.begin(), str.end()));
}

/* 各 i (0 <= i <= n) について部分文字列 [0, i) のハッシュを計算 O(n) */
void RollingHashString::initialize(const std::vector<uint32_t>& str) {
	length_m = str.size();

	hashes_m.clear();
	hashes_m.reserve(str.size() + 1);
	hashes_m.push_back(RollingHash());

	RollingHash hash;
	for (uint32_t element : str) {
		hash.pushBack(element);
		hashes_m.push_back(hash);
	}
}

/* 位置 index から count 要素切り取ってできる文字列のハッシュを得る O(1) */
/* 引数は std::string::substr に合わせている */
RollingHash RollingHashString::substr(int index, int count) {
	int left = index;
	int right = count == -1 ? length_m : std::min(length_m, index + count);
	return RollingHash::removePrefix(hashes_m[right], hashes_m[left]);
}
#ifndef __SETS_H__
#define __SETS_H__

/* updated: 2020-03-28 */

// 集合系の関数などを置きたい

#include <cstdint>
#include <vector>
#include <cassert>

#ifdef _MSC_VER
#include <intrin.h>
#endif

// ビット演算系

/* 立っているビットの数を数える */
inline int popcount(uint64_t value) {
#ifdef _MSC_VER
	return __popcnt64(value);
#elif defined(__GNUC__)
	return __builtin_popcountll(value);
#else
	value = (value & 0x5555555555555555) + ((value >>  1) & 0x5555555555555555);
	value = (value & 0x3333333333333333) + ((value >>  2) & 0x3333333333333333);
	value = (value & 0x0f0f0f0f0f0f0f0f) + ((value >>  4) & 0x0f0f0f0f0f0f0f0f);
	value = (value & 0x00ff00ff00ff00ff) + ((value >>  8) & 0x00ff00ff00ff00ff);
	value = (value & 0x0000ffff0000ffff) + ((value >> 16) & 0x0000ffff0000ffff);
	value = (value & 0x00000000ffffffff) + ((value >> 32) & 0x00000000ffffffff);
	return value;
#endif
}

/* 最上位ビットの位置を返す (0-based, value == 0 のときは -1 を返す) */
/* floor(log2(value)) と一致する */
inline int msbPosition(uint64_t value) {
	value |= value >> 1;
	value |= value >> 2;
	value |= value >> 4;
	value |= value >> 8;
	value |= value >> 16;
	value |= value >> 32;
	return popcount(value) - 1;
}

/* 最下位ビットの位置を返す (0-based, value == 0 のときは 64 を返す) */
inline int lsbPosition(uint64_t value) {
	value |= value << 1;
	value |= value << 2;
	value |= value << 4;
	value |= value << 8;
	value |= value << 16;
	value |= value << 32;
	return 64 - popcount(value);
}

/* 最上位ビットを取得 (value == 0 のときは 0 を返す) */
inline uint64_t msb(uint64_t value) {
	if (value == 0) return uint64_t();
	return uint64_t(1) << msbPosition(value);
}

/* 最下位ビットを取得 (value == 0 のときは 0 を返す) */
/* TODO: これに関しては明らかに value & -value のほうが速いと思うけどどうしようか */
inline uint64_t lsb(uint64_t value) {
	if (value == 0) return uint64_t();
	return uint64_t(1) << lsbPosition(value);
}

/* ceil(log2(value)) を返す (value == 0 のときは -1 を返す) */
/* 戻り値の範囲は -1 <= ret <= 64 */
inline int ceilLog2(uint64_t value) {
	if (value == 0) return -1;
	return msbPosition(value - 1) + 1;
}

/* ビットの並びを逆転させる */
inline uint64_t bitReverse(uint64_t val) {
	val = (val & 0x5555555555555555) <<  1 | (val & 0xAAAAAAAAAAAAAAAA) >>  1;
	val = (val & 0x3333333333333333) <<  2 | (val & 0xCCCCCCCCCCCCCCCC) >>  2;
	val = (val & 0x0F0F0F0F0F0F0F0F) <<  4 | (val & 0xF0F0F0F0F0F0F0F0) >>  4;
	val = (val & 0x00FF00FF00FF00FF) <<  8 | (val & 0xFF00FF00FF00FF00) >>  8;
	val = (val & 0x0000FFFF0000FFFF) << 16 | (val & 0xFFFF0000FFFF0000) >> 16;
	val = (val & 0x00000000FFFFFFFF) << 32 | (val & 0xFFFFFFFF00000000) >> 32;
	return val;
}

/* 下位 digits ビットについてビットの並びを逆転させる (上位ビットは無視) */
inline uint64_t bitReverse(uint64_t val, int digits) {
	assert(digits > 0 || digits <= 64);
	return bitReverse(val) >> (64 - digits);
}

/* 1 << quantity を返す */
inline uint64_t shift(int quantity) {
	return uint64_t(1) << quantity;
}

/* 整数 sets を集合としてみたとき、element 番目の要素を持つかどうか bool(s & (1 << element)) */
inline bool has(uint64_t sets, int element) {
	return sets & shift(element);
}

template <class T>
void bitReverseArray(std::vector<T>& arr);

/* 配列の要素を添字のビット逆順に並べ替える (配列長は2冪) */
template <class T>
void bitReverseArray(std::vector<T>& arr) {
	const int rank = msbPosition(arr.size());
	const int length = 1 << rank;
	assert(int(arr.size()) == length);

	for (int i = 0; i < length; ++i) {
		int j = bitReverse(i, rank);
		if (j > i) {
			std::swap(arr[i], arr[j]);
		}
	}
}


// 畳み込み演算系

template <class T>
void transformSubsetZeta(std::vector<T>& arr);
template <class T>
void transformInverseSubsetZeta(std::vector<T>& arr);
template <class T>
void transformSupersetZeta(std::vector<T>& arr);
template <class T>
void transformInverseSupersetZeta(std::vector<T>& arr);
template <class T>
void transformHadamard(std::vector<T>& vec);
template <class T>
std::vector<T> convolveOnXor(const std::vector<T>& a, const std::vector<T>& b);

/* 逆変換とまとめられないか？ */
/* 高速ゼータ変換 O(n log n), n は2冪 */
/* b[s] = sum[t is a subset of s] a[t] */
template <class T>
void transformSubsetZeta(std::vector<T>& arr) {
	const uint64_t length = arr.size();
	const int level = msbPosition(length);
	assert(length == shift(level));

	for (int k = 0; k < level; ++k) {
		for (uint64_t s = 0; s < length; ++s) {
			if (has(s, k)) continue;
			arr[s] += arr[s | shift(k)];
		}
	}
}

/* 高速ゼータ変換の逆変換 O(n log n), n は2冪 */
template <class T>
void transformInverseSubsetZeta(std::vector<T>& arr) {
	const uint64_t length = arr.size();
	const int level = msbPosition(length);
	assert(length == (uint64_t(1) << level));

	for (int k = 0; k < level; ++k) {
		for (uint64_t s = 0; s < length; ++s) {
			if (has(s, k)) continue;
			arr[s | shift(k)] -= arr[s];
		}
	}
}

/* 高速(上位集合)ゼータ変換 O(n log n), n は2冪 */
/* b[s] = sum[t is a superset of s] a[t] */
template <class T>
void transformSupersetZeta(std::vector<T>& arr) {
	const uint64_t length = arr.size();
	const int level = msbPosition(length);
	assert(length == (uint64_t(1) << level));

	for (int k = 0; k < level; ++k) {
		for (uint64_t s = 0; s < length; ++s) {
			if (has(s, k)) continue;
			arr[s | shift(k)] += arr[s];
		}
	}
}

/* 高速(上位集合)ゼータ変換の逆変換 O(n log n), n は2冪 */
template <class T>
void transformInverseSupersetZeta(std::vector<T>& arr) {
	const uint64_t length = arr.size();
	const int level = msbPosition(length);
	assert(length == (uint64_t(1) << level));

	for (int k = 0; k < level; ++k) {
		for (uint64_t s = 0; s < length; ++s) {
			if (has(s, k)) continue;
			arr[s] -= arr[s | shift(k)];
		}
	}
}

/* 高速アダマール変換 O(n log n), n は2冪 (オーバーフロー注意) */
/* オーバーフロー注意 */
template <class T>
void transformHadamard(std::vector<T>& vec) {
	const int rank = msbPosition(vec.size());
	const int length = 1 << rank;
	assert(vec.size() == length);

	/* バタフライ演算 */
	auto butterfly = [](T& a, T& b) -> void {
		T tmp(a);
		a += b;
		b = tmp - b;
	};

	/* FFT 同様に各ビットについてバタフライ演算を回す */
	for (int cnt = 0; cnt < rank; ++cnt) {
		const int blk_max = length >> (cnt + 1);
		const int blk_size = 1 << (cnt + 1);

		for (int blk = 0; blk < blk_max; ++blk) {
			const int idx_max = 1 << cnt;

			for (int idx = 0; idx < idx_max; ++idx) {
				const int left = (blk * blk_size + idx);
				const int right = left + blk_size / 2;

				butterfly(vec[left], vec[right]);
			}
		}
	}
}

/* xor 畳み込み O(n log n), n は2冪 (オーバーフロー注意) */
/* ret[n] = sum [i xor j == n] (a[i] * b[j]) */
template <class T>
std::vector<T> convolveOnXor(const std::vector<T>& a, const std::vector<T>& b) {
	const int rank = msbPosition(a.size());
	const int size = 1 << rank;
	assert(a.size() == b.size());
	assert(a.size() == size);

	std::vector<T> a_copied = a;
	std::vector<T> b_copied = b;
	transformHadamard(a_copied);
	transformHadamard(b_copied);

	std::vector<T> ret(size);
	for (int i = 0; i < size; ++i) {
		ret[i] = a_copied[i] * b_copied[i];
	}
	transformHadamard(ret);

	/* 関数 transformHadamard はユニタリ変換ではないので係数を調整 */
	/* IntMod など -> 逆元を前計算することも可能 */
	for (int i = 0; i < size; ++i) {
		ret[i] /= size;
	}
	return ret;
}



#endif
#define _CRT_SECURE_NO_WARNINGS
#define _SCL_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <utility>
#include <algorithm>
#include <functional>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <limits>
#include <numeric>
#include <valarray>
#include <fstream>
#include <array>
#include <random>
#include <unordered_set>
#include <unordered_map>

using namespace std;
using uint = uint32_t;
using LL = int64_t;
using ULL = uint64_t;
using PP = pair<LL, LL>;
template <typename T> using PriorityQ = priority_queue<T, vector<T>, greater<T> >;
#define REP(i, a, n) for(LL i = (a), i##_max_ = (n); i < i##_max_; ++i)
#define REM(i, a, n) for(LL i = (LL)(n) - 1, i##_min_ = (a); i >= i##_min_; --i)
#define FLOAT fixed << setprecision(16)
#define SPEEDUP { cin.tie(NULL); ios::sync_with_stdio(false); }
const int INF = 0x3FFFFFFF;
const LL INFLL = 0x3FFFFFFF3FFFFFFF;
const double INFD = 1.0e+308;
const double EPS = 1.0e-9;

void YesNo(bool b) { cout << (b ? "Yes" : "No") << endl; }
void YESNO(bool b) { cout << (b ? "YES" : "NO") << endl; }
template <class T, class U> istream& operator>>(istream& ist, pair<T, U>& right) { return ist >> right.first >> right.second; }
template <class T, class U> ostream& operator<<(ostream& ost, const pair<T, U>& right) { return ost << right.first << ' ' << right.second; }
template <class T, class TCompatible, size_t N> void Fill(T(&dest)[N], const TCompatible& val) { fill(dest, dest + N, val); }
template <class T, class TCompatible, size_t M, size_t N> void Fill(T(&dest)[M][N], const TCompatible& val) { for (int i = 0; i < M; ++i) Fill(dest[i], val); }
template <class T> T Next() { T buf; cin >> buf; return buf; }
istream& Ignore(istream& ist) { string s; ist >> s; return ist; }
bool Inside(int i, int j, int h, int w) { return i >= 0 && i < h&& j >= 0 && j < w; }

#ifdef ONLY_MY_ENVIR
#include "Accumulator.h"
#include "Algebraic.h"
#include "BinaryMatrix.h"
#include "BinaryTree.h"
#include "Bipartite.h"
#include "BIT.h"
#include "Compressor.h"
#include "Decompositions.h"
#include "DiscreteLog.h"
#include "DynamicMod.h"
#include "Exponential.h"
#include "Factorization.h"
#include "FFT.h"
#include "FlowSolver.h"
#include "Geometric2D.h"
#include "Geometric2DFloat.h"
#include "Geometric3D.h"
#include "Geometric3DFloat.h"
#include "Graph.h"
#include "GraphUtil.h"
#include "Interpolation.h"
#include "IntMod.h"
#include "KDTree.h"
#include "LazySegmentTree.h"
#include "LIS.h"
#include "List.h"
#include "Math.h"
#include "MathUtil.h"
#include "Matrix.h"
#include "MinCostFlowSolver.h"
#include "MinMax.h"
#include "Numbers.h"
#include "Optimize.h"
#include "Permutation.h"
#include "Polynomial.h"
#include "Position.h"
#include "Random.h"
#include "Range.h"
#include "Rational.h"
#include "RollingHash.h"
#include "RuntimeMod.h"
#include "SegmentTree.h"
#include "SegmentTree2D.h"
#include "Sets.h"
#include "Shortest.h"
#include "SlidingWindow.h"
#include "SpanningTree.h"
#include "StringSearching.h"
#include "SuffixArray.h"
#include "SwitchList.h"
#include "Timer.h"
#include "Tree.h"
#include "TreeUtil.h"
#include "UnionFind.h"
#include "Util.h"
#include "VectorUtil.h"
#endif

#ifdef __GNUC__
typedef __int128 LLL;
istream& operator>>(istream& ist, __int128& val) { LL tmp; ist >> tmp; val = tmp; return ist; }
ostream& operator<<(ostream& ost, __int128 val) { LL tmp = val; ost << tmp; return ost; }
#endif

int main() {
	int n;
	vector<string> ss;
	cin >> n;
	REP(i, 0, n) ss.push_back(Next<string>());
	sort(ss.begin(), ss.end(), [](auto a, auto b) { return a.size() < b.size(); });

	constexpr int w = 26;
	map<RollingHash, int> mp;
	
	LL sum = 0;
	for (string& s : ss) {
		RollingHashString rs(s);
		int e = 0;
		REP(k, 0, s.size()) {
			e |= shift(s[k] - 'a');
			RollingHash h = rs.substr(k + 1);
			auto it = mp.find(h);
			if (it == mp.end()) continue;
			int f = it->second;
			sum += popcount(e & f);
		}

		{
			RollingHash h = rs.substr(1);
			mp[h] |= shift(s[0] - 'a');
		}
	}
	cout << sum << endl;
	return 0;
}








Measured memory_bytes: 49052