using System;
using System.Collections.Generic;//list用
using System.Text.RegularExpressions;//正規表現用
using System.Text;//StringBuilder用
using System.Collections;//ハッシュテーブル用
using System.Linq;
class Program
{
    Hashtable ht = new Hashtable();
    static List<int> s = new List<int>();
    static int N;
    static StringBuilder str1= new StringBuilder("");//Append(str ○○)関数で文字を追加していく

    static void Main()
    {
        Modular result = new Modular(1);//素数で割った余りを出せで使う★使い方：Modular型で宣言すると、その時点でのその素数で割った余りを保持する変数になる（powべき乗、Fac累乗、nCr組み合わせも関数として存在）。カッコ内は初期値
        //Node no = new Node<>();//UnionFind★Find関数で根っこの値を返す（根っこの値が一緒なら同グループ）、Unite関数で二つの木をくっつける
        //Permutation pe = new Permutation<>();//配列＆リストを並べ替えた場合の全ケースを出力★All関数でリスト形式で返す。
        //Treap tr = new Treap<>();//平衡二分木★Insert()関数で挿入、FindIndex()関数で該当する大きさの物が入るべき配列番号を返す。
        // delegate int CFunc();//下関数に使うデリゲータ。コイツと同じ引数と戻り値で関数作って、下の評価式の部分に関数名※（）いらないを入れる。
        //PriorityQueue pr = new PriorityQueue<>(評価式);//優先度付キュー★Enqueue()で格納、Dequeue()で取りだし。引数は評価式（大と小のどちらが優先か）。
        Read1();
        //Read2(K);
        string tmp = Console.ReadLine();
      //先頭から順に見ていく
      string rgb="";
      int first=0;
      int twos=0;
      for(int i=0;i<3*N;i++)
      {
        if(rgb.Length>0){
      if(rgb[0]==tmp[i]){first++;continue;}
      if(rgb.Length>1){
      if(rgb[1]==tmp[i]){
        if(first>twos){
          result*=first-twos;
          twos++;
                        }else{
          first++;
          rgb=rgb[1].ToString()+rgb[0].ToString();
        }

        continue;}
        else{
        result*=twos;
          first--;twos--;
         if(twos==0){rgb=rgb[0].ToString();}  
          if(first==0){rgb="";}
        }}
        else{
        rgb=rgb[0]+tmp[i].ToString();
          result*=first;twos++;
        }
        
        
        }else
        {
        rgb=tmp[i].ToString();
          first++;
        }
      }
      for(int i=1;i<=N;i++){result*=i;}
        Console.WriteLine(((int)result).ToString());
    }

    static void Read1()
    {
        string tmp = Console.ReadLine();
        N = int.Parse(tmp);
    }

    static void Read2(int kosuu)
    {
        string[] tmp = Console.ReadLine().Split(' ');
        for (int i = 0; i < kosuu; i++) { s.Add(int.Parse(tmp[i])); }
    }


    static long Gcd(long a, long b)
    {
        var v = new[] { a, b };
        while (v[1] != 0) { v = new[] { v[1], v[0] % v[1] }; }
        return v[0];
    }

    static long Lcm(long a, long b)
    {
        return a / Gcd(a, b) * b;
    }


}
class Modular
{
    private const int M = 998244353;//素数
    private long value;
    public Modular(long value) { this.value = value; }
    public static implicit operator Modular(long a)
    {
        var m = a % M;
        return new Modular((m < 0) ? m + M : m);
    }
    public static Modular operator +(Modular a, Modular b)
    {
        return a.value + b.value;
    }
    public static Modular operator -(Modular a, Modular b)
    {
        return a.value - b.value;
    }
    public static Modular operator *(Modular a, Modular b)
    {
        return a.value * b.value;
    }
    private static Modular Pow(Modular a, int n)
    {
        switch (n)
        {
            case 0:
                return 1;
            case 1:
                return a;
            default:
                var p = Pow(a, n / 2);
                return p * p * Pow(a, n % 2);
        }
    }
    public static Modular operator /(Modular a, Modular b)
    {
        return a * Pow(b, M - 2);
    }
    private static readonly List<int> facs = new List<int> { 1 };
    private static Modular Fac(int n)
    {
        for (int i = facs.Count; i <= n; ++i)
        {
            facs.Add((int)(Math.BigMul(facs.Last(), i) % M));
        }
        return facs[n];
    }
    public static Modular Ncr(int n, int r)
    {
        return (n < r) ? 0
        : (n == r) ? 1
        : Fac(n) / (Fac(r) * Fac(n - r));
    }
    public static explicit operator int(Modular a)
    {
        return (int)a.value;
    }

    class Node<T>
    {
        private int m_height;
        private Node<T> m_parent;
        public T Item { get; private set; }
        public Node(T item)
        {
            m_height = 0;
            m_parent = this;
            Item = item;
        }
        public Node<T> Find()
        {
            if (m_parent == this) { return this; }

            Node<T> parent = m_parent.Find();
            m_parent = parent;
            return parent;
        }
        public static void Unite(Node<T> a, Node<T> b)
        {
            Node<T> p = a.Find();
            Node<T> q = b.Find();
            if (p.m_height < q.m_height)
            {
                p.m_parent = q;
                q.m_height = Math.Max(p.m_height + 1, q.m_height);
            }
            else
            {
                q.m_parent = p;
                p.m_height = Math.Max(q.m_height + 1, p.m_height);
            }
        }
    }

    static class Permutation<T>
    {
        private static void Search(List<T[]> perms, Stack<T> stack, T[] a)
        {
            int N = a.Length;
            if (N == 0)
            {
                perms.Add(stack.Reverse().ToArray());
            }
            else
            {
                var b = new T[N - 1];
                Array.Copy(a, 1, b, 0, N - 1);
                for (int i = 0; i < a.Length; ++i)
                {
                    stack.Push(a[i]);
                    Search(perms, stack, b);
                    if (i < b.Length) { b[i] = a[i]; }
                    stack.Pop();
                }
            }
        }
        public static IEnumerable<T[]> All(IEnumerable<T> src)
        {
            var perms = new List<T[]>();
            Search(perms, new Stack<T>(), src.ToArray());
            return perms;
        }
    }

    class Treap<T> where T : IComparable
    {
        private class Node
        {
            private static Random g_rand = new Random();
            private readonly int m_rank = g_rand.Next();
            private readonly T m_value;
            private Node m_lch;
            private Node m_rch;
            private int m_count;

            public Node(T value)
            {
                m_value = value;
                m_count = 1;
            }

            private static int Count(Node node)
            {
                return (node != null) ? node.m_count : 0;
            }

            private Node Update()
            {
                m_count = Count(m_lch) + Count(m_rch) + 1;
                return this;
            }

            public static Node Merge(Node a, Node b)
            {
                if (a == null) { return b; }
                if (b == null) { return a; }

                if (a.m_rank < b.m_rank)
                {
                    a.m_rch = Merge(a.m_rch, b);
                    return a.Update();
                }
                else
                {
                    b.m_lch = Merge(a, b.m_lch);
                    return b.Update();
                }
            }

            public static Tuple<Node, Node> Split(Node t, int k)
            {
                if (t == null) { return new Tuple<Node, Node>(null, null); }

                if (k <= Count(t.m_lch))
                {
                    var pair = Split(t.m_lch, k);
                    t.m_lch = pair.Item2;
                    return new Tuple<Node, Node>(pair.Item1, t.Update());
                }
                else
                {
                    var pair = Split(t.m_rch, k - Count(t.m_lch) - 1);
                    t.m_rch = pair.Item1;
                    return new Tuple<Node, Node>(t.Update(), pair.Item2);
                }
            }

            public int FindIndex(T value)
            {
                int L = Count(m_lch);
                if (value.CompareTo(m_value) < 0)
                {
                    return (m_lch != null) ? m_lch.FindIndex(value) : 0;
                }
                else if (value.CompareTo(m_value) > 0)
                {
                    return (m_rch != null) ? m_rch.FindIndex(value) + L + 1 : L + 1;
                }
                else
                {
                    return L;
                }
            }

            public T this[int i]
            {
                get
                {
                    int L = Count(m_lch);
                    if (i < L)
                    {
                        return m_lch[i];
                    }
                    else if (i > L)
                    {
                        return m_rch[i - L - 1];
                    }
                    else
                    {
                        return m_value;
                    }
                }
            }
        }

        private Node node;

        public void Insert(T value)
        {
            if (node != null)
            {
                int k = node.FindIndex(value);
                var pair = Node.Split(node, k);
                node = Node.Merge(Node.Merge(pair.Item1, new Node(value)), pair.Item2);
            }
            else
            {
                node = new Node(value);
            }
        }

        public int FindIndex(T value)
        {
            return node.FindIndex(value);
        }

        public T this[int i]
        {
            get
            {
                return node[i];
            }
        }
    }

    class PriorityQueue<T>
    {
        private readonly List<T> m_list;
        private readonly Func<T, T, int> m_compare;
        private int m_count;
        public PriorityQueue(Func<T, T, int> compare)
        {
            m_list = new List<T>();
            m_compare = compare;
            m_count = 0;
        }
        private int Add(T value)
        {
            if (m_count == m_list.Count)
            {
                m_list.Add(value);
            }
            else
            {
                m_list[m_count] = value;
            }
            return m_count++;
        }
        private void Swap(int a, int b)
        {
            T tmp = m_list[a];
            m_list[a] = m_list[b];
            m_list[b] = tmp;
        }
        public void Enqueue(T value)//要素格納
        {
            int c = Add(value);
            while (c > 0)
            {
                int p = (c - 1) / 2;
                if (m_compare(m_list[c], m_list[p]) < 0) { Swap(p, c); } else { break; }
                c = p;
            }
        }
        public T Dequeue()//要素取り出し
        {
            T value = m_list[0];
            m_list[0] = m_list[--m_count];
            int p = 0;
            while (true)
            {
                int c1 = p * 2 + 1;
                int c2 = p * 2 + 2;
                if (c1 >= m_count) { break; }
                int c = (c2 >= m_count || m_compare(m_list[c1], m_list[c2]) < 0) ? c1 : c2;
                if (m_compare(m_list[c], m_list[p]) < 0) { Swap(p, c); } else { break; }
                p = c;
            }
            return value;
        }
    }

}

Measured memory_bytes: 18260