module main; // https://kmjp.hatenablog.jp/entry/2015/10/24/0930 より // 文字列処理、数え上げ import std; // 二項係数(Knuthの方法、オーバーフローは考慮していない) long binom(long n, long k) { if (n < k || k < 0) return 0L; if (n - k < k) k = n - k; if (k == 0) return 1L; if (k == 1) return n; static long[long][long] memo; if (n !in memo || k !in memo[n]) { memo[n][k] = binom(n - 1, k - 1) * n / k; } return memo[n][k]; } alias P = Tuple!(Tuple!(long, long), Tuple!(long, long)); Int128 calc(long s, int[] p) { if (p.empty) return Int128(1L); p.sort; Int128 ss = s; if (s > 10_000_000) { if (p.length == 1) { if (p[0] == 1) return ss; if (p[0] == 2) return ss * (ss - 1) / 2; } if (p == [1, 1]) return (ss / 2) * (ss - ss / 2); return Int128(1L << 62); } Int128 pat = 1L; auto que = redBlackTree!( (P a, P b) { return a[0][0] * b[0][1] > a[0][1] * b[0][0]; }, true, P)(); foreach_reverse (r; p) { s -= r; long q = r; que.insert(tuple(tuple(q + 1, 1L), tuple(q, q))); } while (s--) { P r = que.front; que.removeFront; pat = pat * r[0][0] / r[0][1]; if (pat >= 1L << 62) return pat; r[1][0]++; que.insert(tuple(tuple(r[1][0] + 1, r[1][0] + 1 - r[1][1]), r[1])); } return pat; } void main() { // 入力 auto S = readln.split.to!(long[]); auto T = readln.chomp; // 答えの計算と出力 int L = T.length.to!int; auto V = new int[][](26); V[T[0] - 'a'] ~= 1; foreach (i; 0 .. L - 1) { if (T[i] == T[i + 1]) V[T[i + 1] - 'a'][$ - 1]++; else V[T[i + 1] - 'a'] ~= 1; } auto num = new int[](26); foreach (t; T) num[t - 'a']++; Int128 ans = 1L; foreach (i; 0 .. 26) if (num[i] > S[i]) { writeln(0); return; } foreach (i; 0 .. 26) { auto pat = calc(S[i], V[i]); if (pat >= 1L << 62) { writeln("hel"); return; } ans *= pat; if (ans >= 1L << 62) { writeln("hel"); return; } } writeln(ans); }