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)

/**
 * code generated by RHelper
 * More info: https://github.com/mkc1370/RHelper
 * @author 
 */

using Task.DDivGame;

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

namespace Task.DDivGame
{
    public class DDivGame
    {
        public void Solve()
        {
            var n = CINL;
            var a = new Factorization(n);
            var t = a.Calc().ToList().Distinct().ToList();
            var sum = 0L;
            foreach (var tt in t)
            {
                var h = 0;
                while (true)
                {
                    if (n % (long)Math.Pow(tt, h + 1) == 0)
                    {
                        n /= (long)Math.Pow(tt, h + 1);
                        h++;
                    }
                    else
                    {
                        break;
                    }
                }

                sum += h;
            }
            COUT(sum);
        }
        
        private readonly StringReader cin;
        private readonly StringWriter cout;
        private readonly Scanner scanner;

        public DDivGame(StringReader cin, StringWriter cout)
        {
            this.cin = cin;
            this.cout = cout;
            scanner = new Scanner(cin);
        }

        private long CINL => scanner.Long();
        private double CIND => scanner.Double();
        private string CINS => scanner.String();
        private static IEnumerable<T> Repeat<T>(T v, long n) => Enumerable.Repeat(v, (int)n);
        private List<long> CINVL(long n) => Repeat(0, n).Select(_ => CINL).ToList();
        private List<double> CINVD(long n) => Repeat(0, n).Select(_ => CIND).ToList();
        private List<string> CINVS(long n) => Repeat(0, n).Select(_ => CINS).ToList();

        private void COUT(object o) => cout.WriteLine(o);
        
        private void Yes(bool value) => cout.WriteLine(value ? "Yes" : "No");
        private void YES(bool value) => cout.WriteLine(value ? "YES" : "NO");
        private void Possible(bool value) => cout.WriteLine(value ? "Possible" : "Impossible");
        private void POSSIBLE(bool value) => cout.WriteLine(value ? "POSSIBLE" : "IMPOSSIBLE");
    }
    
    public class Factorization
    {
        private static long N;

        public Factorization(long n) { N = n; }

        //最大公約数を返す
        public static long GCD(long a, long b)
        {
            if (a < b) return GCD(b, a);
            long r;
            while (b != 0)
            {
                r = a % b;
                a = b;
                b = r;
            }
            return a;
        }

        //素数判定
        public static bool IsPrime(long n)
        {
            if (n < 2) return false;
            if (n == 2) return true;
            if (n % 2 == 0) return false;

            double root = Math.Sqrt(n);
            for (int i = 3; i <= root; i += 2)
            {
                if (n % i == 0) return false;
            }
            return true;
        }

        //試し割り
        private static int[] TryPrimes = new int[] { 2, 3, 5, 7, 11 };
        public long TryAllocation(long p)
        {
            long count = 0;
            while (N % p == 0)
            {
                count++;
                N /= p;
            }
            return count;
        }

        private int[] xi = new int[] { 13, 17, 19, 23, 29 };
        private long f(long x, int suffix)
        {
            return (xi[suffix % xi.Count()] * x + suffix) % N;
        }

        //nを分解
        public long PollardsRho(long n, int suffix = 0)
        {
            //素数を渡すと失敗するらしい
            if (IsPrime(n)) return n; //もう素数
            long x = 2, y = 2, d = 1;
            while (d == 1)
            {
                x = f(x, suffix);
                y = f(f(y, suffix), suffix);
                d = GCD(Math.Abs(x - y), n);
            }
            if (d == n)
            {
                //f(x)を変えて試す
                return PollardsRho(n, suffix + 1);
            }
            return d;
        }

        public IEnumerable<long> Calc()
        {
            //小さな素因数の計算
            foreach (var prime in TryPrimes)
            {
                var box = TryAllocation(prime);
                for (int i = 0; i < box; i++) yield return prime;
            }

            //残りをRhoで解く
            while (true)
            {
                if (N == 1) break;
                var ret = PollardsRho(N);
                yield return ret;
                N /= ret;
            }
        }
    }

    public static class MathEx
    {
        // O (log N)
        public static long Gcd(long n, long m)
        {
            n = Math.Abs(n);
            m = Math.Abs(m);
            while (n != 0)
            {
                m %= n;
                if (m == 0) return n;
                n %= m;
            }

            return m;
        }

        // O (log N)
        public static long Lcm(long n, long m)
        {
            return n / Gcd(n, m) * m;
        }

        // O (N log log N)
        public static bool[] GetPrimeList(int max, List<int> primes = null)
        {
            var isPrime = new bool[max + 1];
            for (var i = 2; i < isPrime.Length; i++) isPrime[i] = true;
            for (var i = 2; i * i <= max; i++)
                if (!isPrime[i]) continue;
                else
                    for (var j = i * i; j <= max; j += i)
                        isPrime[j] = false;
            if (primes != null)
                for (var i = 0; i <= max; i++)
                    if (isPrime[i])
                        primes.Add(i);

            return isPrime;
        }

        // O (N)
        public static T Max<T>(params T[] array) where T : IComparable
        {
            var max = array[0];
            foreach (var value in array)
            {
                if (max.CompareTo(value) < 0)
                    max = value;
            }

            return max;
        }

        // O (N)
        public static T Min<T>(params T[] array) where T : IComparable
        {
            var min = array[0];
            foreach (var value in array)
            {
                if (min.CompareTo(value) > 0)
                    min = value;
            }

            return min;
        }

        public static void Swap<T>(ref T lhs, ref T rhs)
        {
            var temp = lhs;
            lhs = rhs;
            rhs = temp;
        }
    }

    public class Scanner
    {
        public Scanner(StringReader stringReader)
        {
            this.stringReader = stringReader;
        }

        private readonly StringReader stringReader;
        private readonly char[] buffer = new char[1024];
        private int len, ptr;
        private bool isEof;

        private char Read()
        {
            if (isEof) throw new EndOfStreamException();
            if (ptr >= len)
            {
                ptr = 0;
                if ((len = stringReader.Read(buffer, 0, 1024)) <= 0)
                {
                    isEof = true;
                    return '\0';
                }
            }

            return buffer[ptr++];
        }

        public char Char()
        {
            char b;
            do b = Read();
            while (b < 33 || 126 < b);
            return b;
        }

        public string String()
        {
            var sb = new StringBuilder();
            for (char b = Char(); b >= 33 && b <= 126; b = Read())
                sb.Append(b);
            return sb.ToString();
        }

        public long Long()
        {
            long ret = 0;
            char b;
            var ng = false;
            do b = Read();
            while (b != '-' && (b < '0' || '9' < b));
            if (b == '-')
            {
                ng = true;
                b = Read();
            }

            for (;; b = Read())
            {
                if (b < '0' || '9' < b)
                    return ng ? -ret : ret;
                else ret = ret * 10 + b - '0';
            }
        }

        public double Double()
        {
            return double.Parse(String(), CultureInfo.InvariantCulture);
        }
    }

    public struct ModInt {
        public const long Mod = (int)1e9 + 7;

        public long num;
        public ModInt(long n) { num = n; }
        public override string ToString() { return num.ToString(); }
        public static ModInt operator +(ModInt l, ModInt r) { l.num += r.num; if (l.num >= Mod) l.num -= Mod; return l; }
        public static ModInt operator -(ModInt l, ModInt r) { l.num -= r.num; if (l.num < 0) l.num += Mod; return l; }
        public static ModInt operator *(ModInt l, ModInt r) { return new ModInt(l.num * r.num % Mod); }
        public static implicit operator ModInt(long n) { n %= Mod; if (n < 0) n += Mod; return new ModInt(n); }

        public static ModInt Pow(ModInt v, long k) { return Pow(v.num, k); }

        // O(N log N)
        public static ModInt Pow(long v, long k) {
            long ret = 1;
            for (k %= Mod - 1; k > 0; k >>= 1, v = v * v % Mod)
                if ((k & 1) == 1) ret = ret * v % Mod;
            return new ModInt(ret);
        }
        // O(log N)
        public static ModInt Inverse(ModInt v) { return Pow(v, Mod - 2); }
    }
    public class BinomialCoefficient {
        public ModInt[] fact, ifact;
        public BinomialCoefficient(int n) {
            fact = new ModInt[n + 1];
            ifact = new ModInt[n + 1];
            fact[0] = 1;
            for (int i = 1; i <= n; i++)
                fact[i] = fact[i - 1] * i;
            ifact[n] = ModInt.Inverse(fact[n]);
            for (int i = n - 1; i >= 0; i--)
                ifact[i] = ifact[i + 1] * (i + 1);
            ifact[0] = ifact[1];
        }
        public ModInt this[int n, int r] {
            get {
                if (n < 0 || n >= fact.Length || r < 0 || r > n) return 0;
                return fact[n] * ifact[n - r] * ifact[r];
            }
        }
        public ModInt RepeatedCombination(int n, int k) {
            if (k == 0) return 1;
            return this[n + k - 1, k];
        }
    }
}


public class Output
{
	public static void Main()
	{
		var reader = new System.IO.StringReader(Console.In.ReadToEnd());
		var writer = new System.IO.StringWriter();
		var solver = new DDivGame(reader, writer);
		solver.Solve();
		System.Console.Write(writer.GetStringBuilder().ToString());
	}
}