using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using static System.Math; using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute; using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions; public static class P { public static void Main() { int n = int.Parse(Console.ReadLine()); var a = Console.ReadLine().Split().Select(int.Parse).ToArray(); var ordered = a.Distinct().OrderBy(x => x).ToArray(); var dic = ordered.Select((elem, ind) => (elem, ind)).ToDictionary(x => x.elem, x => x.ind); a = a.Select(x => dic[x]).ToArray(); (ModInt val, ModInt cnt)[] lRes = new (ModInt val, ModInt cnt)[n]; { var segTree = new SegmentTree<(ModInt, ModInt)>(ordered.Length, (0, 0), (x, y) => (x.Item1 + y.Item1, x.Item2 + y.Item2)); for (int i = 0; i < lRes.Length; i++) { lRes[i] = segTree.Query(a[i] + 1, ordered.Length - 1); segTree.Operate(a[i], (ordered[a[i]], 1)); } } (ModInt val, ModInt cnt)[] rRes = new (ModInt val, ModInt cnt)[n]; { var segTree = new SegmentTree<(ModInt, ModInt)>(ordered.Length, (0, 0), (x, y) => (x.Item1 + y.Item1, x.Item2 + y.Item2)); for (int i = rRes.Length - 1; i >= 0; i--) { rRes[i] = segTree.Query(0, a[i] - 1); segTree.Operate(a[i], (ordered[a[i]], 1)); } } ModInt res = 0; for (int i = 0; i < n; i++) { var (lVal, lCnt) = lRes[i]; var (rVal, rCnt) = rRes[i]; var sum = lVal * rCnt + rVal * lCnt + ordered[a[i]] * lCnt * rCnt; res += sum; } Console.WriteLine(res); } } class SegmentTree { public int Size { get; private set; } T Identity; T[] Data; Func Merge; int LeafCount; [MethodImpl(MethodImplOptions.AggressiveInlining)] public SegmentTree(int size, T identity, Func merge) { Init(size, identity, merge); for (int i = 1; i < Data.Length; i++) Data[i] = identity; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public SegmentTree(T[] elems, T identity, Func merge) { Init(elems.Length, identity, merge); elems.CopyTo(Data, LeafCount); for (int i = elems.Length + LeafCount; i < Data.Length; i++) Data[i] = identity; for (int i = LeafCount - 1; i >= 1; i--) Data[i] = Merge(Data[i << 1], Data[(i << 1) | 1]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Init(int size, T identity, Func merge) { Size = size; Identity = identity; Merge = merge; LeafCount = 1; while (LeafCount < size) LeafCount <<= 1; Data = new T[LeafCount << 1]; } public T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return Data[LeafCount + index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] set { Update(index, value); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Update(int i, T x) { Data[i += LeafCount] = x; while (0 < (i >>= 1)) Data[i] = Merge(Data[i << 1], Data[(i << 1) | 1]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Operate(int i, T x) { i += LeafCount; Data[i] = Merge(Data[i], x); while (0 < (i >>= 1)) Data[i] = Merge(Data[i << 1], Data[(i << 1) | 1]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Query(int l, int r) { T lRes = Identity, rRes = Identity; for (l += LeafCount, r += LeafCount; l <= r; l = (l + 1) >> 1, r = (r - 1) >> 1) { if ((l & 1) == 1) lRes = Merge(lRes, Data[l]); if ((r & 1) == 0) rRes = Merge(Data[r], rRes); } return Merge(lRes, rRes); } } struct ModInt { public const int Mod = 998244353; const long POSITIVIZER = ((long)Mod) << 31; long Data; public ModInt(long data) { if ((Data = data % Mod) < 0) Data += Mod; } public static implicit operator long(ModInt modInt) => modInt.Data; public static implicit operator ModInt(long val) => new ModInt(val); public static ModInt operator +(ModInt a, int b) => new ModInt() { Data = (a.Data + b + POSITIVIZER) % Mod }; public static ModInt operator +(ModInt a, long b) => new ModInt(a.Data + b); public static ModInt operator +(ModInt a, ModInt b) { long res = a.Data + b.Data; return new ModInt() { Data = res >= Mod ? res - Mod : res }; } public static ModInt operator -(ModInt a, int b) => new ModInt() { Data = (a.Data - b + POSITIVIZER) % Mod }; public static ModInt operator -(ModInt a, long b) => new ModInt(a.Data - b); public static ModInt operator -(ModInt a, ModInt b) { long res = a.Data - b.Data; return new ModInt() { Data = res < 0 ? res + Mod : res }; } public static ModInt operator *(ModInt a, int b) => new ModInt(a.Data * b); public static ModInt operator *(ModInt a, long b) => a * new ModInt(b); public static ModInt operator *(ModInt a, ModInt b) => new ModInt() { Data = a.Data * b.Data % Mod }; public static ModInt operator /(ModInt a, ModInt b) => new ModInt() { Data = a.Data * GetInverse(b) % Mod }; public static bool operator ==(ModInt a, ModInt b) => a.Data == b.Data; public static bool operator !=(ModInt a, ModInt b) => a.Data != b.Data; public override string ToString() => Data.ToString(); public override bool Equals(object obj) => (ModInt)obj == this; public override int GetHashCode() => (int)Data; static long GetInverse(long a) { long div, p = Mod, x1 = 1, y1 = 0, x2 = 0, y2 = 1; while (true) { if (p == 1) return x2 + Mod; div = a / p; x1 -= x2 * div; y1 -= y2 * div; a %= p; if (a == 1) return x1 + Mod; div = p / a; x2 -= x1 * div; y2 -= y1 * div; p %= a; } } }