Problem:
Score : 400 points

Problem Statement

Given is a positive integer N. Consider repeatedly applying the operation below on N:

First, choose a positive integer z satisfying all of the conditions below:

z can be represented as z=p^e, where p is a prime number and e is a positive integer;

z divides N;

z is different from all integers chosen in previous operations.

Then, replace N with N/z.

Find the maximum number of times the operation can be applied.

Constraints

All values in input are integers.

1 \leq N \leq 10^{12}

Input

Input is given from Standard Input in the following format:

N

Output

Print the maximum number of times the operation can be applied.

Sample Input 1

24

Sample Output 1

3

We can apply the operation three times by, for example, making the following choices:

Choose z=2 (=2^1). (Now we have N=12.)

Choose z=3 (=3^1). (Now we have N=4.)

Choose z=4 (=2^2). (Now we have N=1.)

Sample Input 2

1

Sample Output 2

0

We cannot apply the operation at all.

Sample Input 3

64

Sample Output 3

3

We can apply the operation three times by, for example, making the following choices:

Choose z=2 (=2^1). (Now we have N=32.)

Choose z=4 (=2^2). (Now we have N=8.)

Choose z=8 (=2^3). (Now we have N=1.)

Sample Input 4

1000000007

Sample Output 4

1

We can apply the operation once by, for example, making the following choice:

z=1000000007 (=1000000007^1). (Now we have N=1.)

Sample Input 5

997764507000

Sample Output 5

7

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;

namespace AtCoder2
{
    public class MainClass
    {
        public static void Main(string[] args)
        {
            var sw = new StreamWriter(Console.OpenStandardOutput(), Console.Out.Encoding);
            sw.AutoFlush = false;
            Console.SetOut(sw);

            if (args.Length > 0 && args[0] == "debug")
            {
                var inputs = new[] { @"
24
				", @"
1
                ", @"
64
				", @"
1000000007
				", @"
997764507000
				" };

                foreach (var str in inputs)
                {
                    var text = str.Trim();
                    if (text.Length == 0) continue;
                    var reader = new System.IO.StringReader(text);
                    Console.SetIn(reader);
                    Main2(args);
                    Console.WriteLine("----------------------------------");
                }
            }
            else
                Main2(args);

            Console.Out.Flush();
        }

        public static void Main2(string[] args)
        {
            checked
            {
                var N = long.Parse(Console.ReadLine());
                var res = MathPlus.Prime(N)
                    .GroupBy(n => n)
                    .Select(g => Cnt(g.Count()))
                    .Sum();

                Console.WriteLine(res);
            }
        }

        private static int Cnt(int n)
        {
            int i = 1;
            while (true)
            {
                n -= i;
                if (n < 0) return i - 1;
                i++;
            }
        }

        private static void Assert(bool cond)
        {
            if (!cond) throw new Exception();
        }
    }

    public static class EnumerablePlus
    {
        ///<summary>出力文字列に変換。</summary>
        public static string MkString<T>(this IEnumerable<T> list)
        {
            return list.Aggregate(
                new System.Text.StringBuilder(),
                (a, b) => ((a.Length > 0) ? a.Append(' ') : a).Append(b)
                ).ToString();
        }

        ///<summary>添字付きfor。</summary>
        public static void ForEach2<T>(this IEnumerable<T> list, Action<T, long> a)
        {
            long i = 0;
            foreach (var item in list)
            {
                a(item, i);
            }
        }

        ///<summary>添字付きfor。</summary>
        public static void ForEach<T>(this IEnumerable<T> list, Action<T> a)
        {
            foreach (var item in list)
            {
                a(item);
            }
        }

        ///<summary>指定回数デリゲートを呼び出す。</summary>
        public static IEnumerable<T> Repeat<T>(long n, Func<T> f)
        {
            for (long i = 0; i < n; i++)
            {
                yield return f();
            }
        }

        ///<summary>条件付きMin。</summary>
        public static T MinBy<T, U>(this IEnumerable<T> xs, Func<T, U> key) where U : IComparable<U>
        {
            return xs.Aggregate((a, b) => key(a).CompareTo(key(b)) <= 0 ? a : b);
        }

        ///<summary>条件付きMax。</summary>
        public static T MaxBy<T, U>(this IEnumerable<T> xs, Func<T, U> key) where U : IComparable<U>
        {
            return xs.Aggregate((a, b) => key(a).CompareTo(key(b)) >= 0 ? a : b);
        }

        ///<summary>条件付きMax。複数の値を返す。</summary>
        public static List<T> MaxBy2<T, U>(this IEnumerable<T> xs, Func<T, U> key) where U : IComparable<U>
        {
            return xs.Aggregate(
                new List<T>(),
                (list, b) =>
                {
                    if (list.Count == 0) { list.Add(b); return list; }

                    var aa = key(list[0]);
                    var bb = key(b);

                    if (aa.CompareTo(bb) < 0) list.Clear();

                    if (aa.CompareTo(bb) <= 0) { list.Add(b); return list; }

                    return list;
                });
        }

        ///<summary>複数の値を返す。</summary>
        public static List<T> Max2<T>(this IEnumerable<T> xs) where T : IComparable<T>
        {
            return xs.MaxBy2(o => o);
        }

        ///<summary>リスト内の値を移動する。</summary>
        public static void Move<T>(this IList<T> list, int from, int to)
        {
            var item = list[from];

            for (var idx = from; idx > to; --idx)
            {
                list[idx] = list[idx - 1];
            }

            list[to] = item;
        }

        ///<summary>リスト内の値を移動する。</summary>
        public static T LastOrValue<T>(this IList<T> list, T value)
        {
            return list.Count > 0 ? list.Last() : value;
        }

        ///<summary>辞書をMultiSetとして使うときのAdd。</summary>
        public static void Add2<T>(this IDictionary<T, int> xs, T key)
        {
            if (xs.ContainsKey(key))
                xs[key]++;
            else
                xs.Add(key, 1);
        }
    }

    public static class MathPlus
    {
        ///<summary>約数。順番は不定。</summary>
        public static List<long> Divisor(long n)
        {
            var list = Prime(n).
                GroupBy(id => id).
                Select(pair => new { prime = pair.Key, power = pair.Count() }).
                ToList();

            var result = list.Aggregate(new List<long>(), (left, pair) =>
            {
                var list2 = Enumerable.
                    Range(0, pair.power + 1).
                    Aggregate(new List<long>(), (res, l) =>
                    {
                        var next = res.Count > 0 ? res.Last() * pair.prime : 1L;
                        res.Add(next);
                        return res;
                    });

                if (left.Count == 0) return list2.ToList();

                return list2.
                    SelectMany(l => left.Select(m => l * m)).
                    ToList();
            });

            return result;
        }

        ///<summary>順列の数。</summary>
        public static long Permutation(long n, long r)
            => Factorial(n, r);

        ///<summary>組合せの数。</summary>
        public static long Combination(long n, long r)
        {
            if (r == 0) return 1;

            return Factorial(n, r) / Factorial(r);
        }

        ///<summary>階乗。カウントも指定可能。</summary>
        public static long Factorial(long a, long count = long.MaxValue)
        {
            long res = 1;

            for (long i = 0; a > 0 && i < count; i++)
            {
                checked { res *= a; }
                --a;
            }

            return res;
        }

        ///<summary>素因数分解。昇順。</summary>
        public static List<long> Prime(long a)
        {
            var res = new List<long>();

            var a2 = Math.Ceiling(Math.Sqrt(a));
            for (long b = 2; b <= a2; ++b)
            {
                while (a % b == 0)
                {
                    res.Add(b);
                    a = a / b;
                    a2 = Math.Ceiling(Math.Sqrt(a));
                }
            }

            if (a > 1) res.Add(a);
            return res;
        }

        ///<summary>最小公倍数。</summary>
        public static long Lcm(IEnumerable<long> list)
        {
            return list.Aggregate((a, b) => Lcm(a, b));
        }

        ///<summary>最小公倍数。</summary>
        public static long Lcm(long a, long b)
        {
            return checked(a * b) / Gcd(a, b);
        }

        ///<summary>最大公約数。</summary>
        public static long Gcd(IEnumerable<long> list)
        {
            return list.Aggregate((a, b) => Gcd(a, b));
        }

        ///<summary>最大公約数。</summary>
        public static long Gcd(long a, long b)
        {
            if (a < b)
                Gcd(b, a);

            while (b != 0)
            {
                var rem = a % b;
                a = b;
                b = rem;
            }

            return a;
        }

        ///<summary>整数の切り上げ。</summary>
        public static long Ceiling(long a, long b) => (a + (b - 1)) / b;

        ///<summary>区間内の合計。beginも１から？</summary>
        public static ulong Sum(ulong begin, ulong end)
        {
            var up = Sum(end);
            var low = Sum(begin - 1);
            return up - low;
        }

        ///<summary>1からの合計。</summary>
        public static ulong Sum(ulong end) => checked((end + 1) * end / 2);

    }
}