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: Time Limit Exceeded)

using System;
using System.Numerics;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.IO;
using System.Linq;
using System.Text;
using static System.Console;
using static System.Math;
using static Ex;
using System.Runtime.InteropServices.ComTypes;
using System.Net.Mail;
using Microsoft.VisualBasic;

class AC
{
    /*------------------------------------------------------------------*/

    Dictionary<long, long> PrimeFactor(long n)
    {
        var ret = new Dictionary<long, long>();
        var i = 2;
        while (i <= n)
        {
            if (!ret.ContainsKey(i)) ret[i] = 0;
            while (n % i == 0)
            {
                ret[i]++;
                n /= i;
            }
            i++;
        }
        return ret.Where(kp => kp.Value != 0).ToDictionary(kp => kp.Key, kp => kp.Value);
    }
    void Solve()
    {
        io.I(out long N);
        var set = new HashSet<long>() { 1 };
        List<long> getDivisor(long N)
        {
            var divisor = new List<long>();
            for (var i = 1L; i * i <= N; i++)
            {
                //WriteLine(i);
                if (N % i == 0)
                {
                    divisor.Add(i);
                    if (i != N / i)
                    {
                        divisor.Add(N / i);
                    }
                }
            }
            return divisor;
        }
        bool check(long n)
        {
            return PrimeFactor(n).Keys.Count == 1;
        }
        var ans = 0;
        while (true)
        {
            var divisor = getDivisor(N).OrderBy(x => x);

            var x = divisor.Where(x => !set.Contains(x) && N % x == 0 && check(x));
            if (x.Any())
            {
                var head = x.First();
                set.Add(head);
                head.Log();
                ans++;
                N /= head;
            }
            else break;
        }
        WriteLine(ans);
    }
    /*------------------------------------------------------------------*/
    void Test()
    {
        //--- TEST ---//
    }
    public static void Main(string[] args) => new AC().Stream();
    IO io = new IO();
    private void Stream()
    {
        /*
        var exStdIn = new System.IO.StreamReader("stdin.txt");
        SetIn(exStdIn);
        Test();
        */
        Solve();
        io.Flush();
    }
}
class IO
{
    #region INPUT
    #region FastRead
    private const int Size = 1 << 12;
    private readonly Stream _stream = OpenStandardInput();
    private readonly byte[] _buffer = new byte[Size];
    private int _ptr = 0, _buffLen = 0;
    private bool HasNextByte()
    {
        if (_ptr < _buffLen) return true;
        _ptr = 0;
        _buffLen = _stream.Read(_buffer, 0, Size);
        return _buffLen > 0;
    }
    private byte ReadByte() => HasNextByte() ? _buffer[_ptr++] : throw new EndOfStreamException();

    private bool IsAscii(int c) => '!' <= c && c <= '~';
    private char NextChar()
    {
        var b = ReadByte();
        while (!IsAscii(b)) b = ReadByte();
        return (char)b;
    }
    private string Next()
    {
        var sb = new StringBuilder();
        for (var b = NextChar(); IsAscii(b); b = (char)ReadByte()) sb.Append(b);
        return sb.ToString();
    }
    public string String => Next();
    public char Char => NextChar();
    public int Int => int.Parse(Next());
    public long Long => long.Parse(Next());
    public double Double => double.Parse(Next());
    #endregion
    #region LazyRead
    private void Scan<T>(ref T x)
    {
        if (x is int) __refvalue(__makeref(x), int) = int.Parse(Next());
        else if (x is long) __refvalue(__makeref(x), long) = long.Parse(Next());
        else if (x is double) __refvalue(__makeref(x), double) = double.Parse(Next());
        else if (x is char) __refvalue(__makeref(x), char) = NextChar();
        else if (x is uint) __refvalue(__makeref(x), uint) = uint.Parse(Next());
        else if (x is ulong) __refvalue(__makeref(x), ulong) = ulong.Parse(Next());
        else __refvalue(__makeref(x), string) = Next();
    }
    public void I<T>(out T t)
    {
        t = default;
        Scan(ref t);
    }

    public void I<T, TU>(out T t, out TU u)
    {
        I(out t);
        I(out u);
    }
    public void I<T, TU, TV>(out T t, out TU u, out TV v)
    {
        I(out t, out u);
        I(out v);
    }
    public void I<T, TU, TV, TW>(out T t, out TU u, out TV v, out TW w)
    {
        I(out t, out u);
        I(out v, out w);
    }
    public void I<T, TU, TV, TW, TX>(out T t, out TU u, out TV v, out TW w, out TX x)
    {
        I(out t, out u, out v);
        I(out w, out x);
    }
    public void I<T, TU, TV, TW, TX, TY>(out T t, out TU u, out TV v, out TW w, out TX x, out TY y)
    {
        I(out t, out u, out v);
        I(out w, out x, out y);
    }
    public void I<T>(out T[] a, int n)
    {
        T[] ts = new T[n];
        a = ts;
        for (int i = 0; i < n; ++i) I(out a[i]);
    }
    public void I<T, TU>(out T[] a, out TU[] b, int n)
    {
        a = new T[n];
        b = new TU[n];
        for (int i = 0; i < n; ++i) I(out a[i], out b[i]);
    }
    public void I<T, TU, TV>(out T[] a, out TU[] b, out TV[] c, int n)
    {
        a = new T[n];
        b = new TU[n];
        c = new TV[n];
        for (var i = 0; i < n; ++i) I(out a[i], out b[i], out c[i]);
    }
    public void I<T>(out T[,] a, int h, int w)
    {
        a = new T[h, w];
        for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) I(out a[i, j]);
    }
    #endregion
    #endregion
    #region OUTPUT
    private readonly StreamWriter _sw = new StreamWriter(OpenStandardOutput())
    {
#if DEBUG
        AutoFlush = true
#else
        AutoFlush = false
#endif
    };
    public void Flush() => Out.Flush();
    public void YN(bool f) => yn(f, "YES", "NO");
    public void Yn(bool f) => yn(f, "Yes", "No");
    public void yn(bool f, string y = "yes", string n = "no") => WriteLine(f ? y : n);
    #endregion
    public IO() { SetOut(_sw); }
}
static class Ex
{
    #region マクロもどき
    public static T ID<T>(T x) => x;
    public static Dictionary<T1, T2> MERGE<T1, T2>(Dictionary<T1, T2> xs, Dictionary<T1, T2> ys) => xs.Except(xs.Join(ys, z => z.Key, z => z.Key, (a, b) => a)).Concat(ys).ToDictionary(z => z.Key, z => z.Value);
    public static void FOR(int a, int b, Action<int> f) => FOR(a, b, 1, f);
    public static void FOR(int a, int b, int n, Action<int> f)
    {
        for (int i = a; i < b; i += n) f(i);
    }
    public static void REP(int a, Action<int> f) => FOR(0, a, f);
    public static void REPEQ(int a, Action<int> f) => FOR(0, a + 1, f);
    public static void FOREQ(int a, int b, Action<int> f) => FOR(a, b + 1, f);
    public static void FOREQ(int a, int b, int n, Action<int> f) => FOR(a, b + 1, n, f);
    public static void REP(int a, int b, Action<int, int> f) => REP(a, i => REP(b, j => f(i, j)));
    public static void REP(int a, int b, int c, Action<int, int, int> f) => REP(a, i => REP(b, j => REP(c, k => f(i, j, k))));
    public static void REPEQ(int a, int b, Action<int, int> f) => REPEQ(a, i => REPEQ(b, j => f(i, j)));
    public static void REPEQ(int a, int b, int c, Action<int, int, int> f) => REPEQ(a, i => REPEQ(b, j => REPEQ(c, k => f(i, j, k))));
    public static T MIN<T>(params T[] xs) => xs.Min();
    public static T MAX<T>(params T[] xs) => xs.Max();
    public static IEnumerable<int> RANGE(int s, int e) => Enumerable.Range(s, e - s + 1);
    public static int LCM(int a, int b) => a * (b / GCD(a, b));
    public static int GCD(int a, int b) => (a < b) ? GCD(b, a) : b == 0 ? a : GCD(b, a % b);
    public static int LCM(params int[] xs) => xs.Aggregate(LCM);
    public static int GCD(params int[] xs) => xs.Aggregate(GCD);
    public static long LCM(long a, long b) => a * (b / GCD(a, b));
    public static long GCD(long a, long b) => (a < b) ? GCD(b, a) : b == 0L ? a : GCD(b, a % b);
    public static long LCM(params long[] xs) => xs.Aggregate(LCM);
    public static long GCD(params long[] xs) => xs.Aggregate(GCD);
    #endregion
    #region 拡張メソッド
    public static void Rep(this int x, Action<int> f) => REP(x, f);
    public static void RepEq(this int x, Action<int> f) => REPEQ(x, f);
    public static int ToInt(this string s)
    {
        int.TryParse(s.TrimStart('0'), out int n);
        return n;
    }
    public static int ToInt(this char c) => ToInt(c.ToString());
    public static int ToInt(this char[] c) => ToInt(new string(c));
    public static long ToLong(this string s)
    {
        long.TryParse(s.TrimStart('0'), out long n);
        return n;
    }
    public static long ToLong(this int x) => (long)x;
    public static IEnumerable<long> ToLong(this IEnumerable<int> xs) => xs.Select(x => x.ToLong());
    public static long ToLong(this char c) => ToLong(c.ToString());
    public static long ToLong(this char[] c) => ToLong(new string(c));
    public static int ToMod(this int x, int mod = (int)(1e9 + 7)) => x % mod;
    public static long ToMod(this long x, long mod = (long)(1e9 + 7)) => x % mod;
    public static void Do<T>(this T x, Action<T> f) => f(x);
    public static TU Then<T, TU>(this T x, Func<T, TU> f) => f(x);
    public static bool IsIn<T>(this T[] xs, int i) => 0 <= i && i < xs.Length;
    public static bool IsIn<T>(this T[,] xxs, int i, int j) => 0 <= i && i < xxs.GetLength(0) && 0 <= j && j < xxs.GetLength(1);
    public static void Iter<T>(this IEnumerable<T> xs, Action<T> f)
    {
        foreach (var x in xs) f(x);
    }
    public struct IndexedItem<T>
    {
        public int Index;
        public T Value;
        public IndexedItem(int idx, T val) => (Index, Value) = (idx, val);
    }
    public static IEnumerable<IndexedItem<T>> Indexed<T>(this IEnumerable<T> xs) => xs.Select((x, i) => new IndexedItem<T>(i, x));
    public static void Set<T>(this T[] xs, T v) => REP(xs.Length, i => xs[i] = v);
    public static void Set<T>(this T[,] xxs, T v) => REP(xxs.GetLength(0), i => REP(xxs.GetLength(1), j => xxs[i, j] = v));
    public static string Pad0<T>(this T s, int n) => s.ToString().PadLeft(n, '0');
    public static int RoundOff(this double v, int n) => (int)Round(v, n - 1, MidpointRounding.AwayFromZero);
    public static int RoundUp(this double v) => (int)Ceiling(v);
    public static int RoundDown(this double v) => (int)Floor(v);
    public static bool Odd(this int v) => (v & 1) != 0;
    public static bool Odd(this long v) => (v & 1) != 0;
    public static bool Eve(this int v) => !v.Odd();
    public static bool Eve(this long v) => !v.Odd();
    public static void Prt<T>(this T x) => WriteLine(x);
    public static void Prt<T>(this T[] xs) => xs.Iter(x => WriteLine(x));
    public static void Prt<T>(this List<T> xs) => xs.Iter(x => WriteLine(x));
    public static void Prt<T>(this T[,] xs) => xs.GetLength(0).Rep(i =>
    {
        xs.GetLength(1).Rep(j => Write($"{xs[i, j]} "));
        WriteLine();
    });
    public static void Prt_<T>(this T[] xs) => WriteLine(string.Join(" ", xs));
    public static void Log<T>(this T x, [CallerLineNumber] int line = 0)
    {
#if DEBUG
        Error.WriteLine($"--- LOG[{line}]: {x} ---");
#endif
    }
    public static void Log<T>(this T[] xs, [CallerLineNumber] int line = 0)
    {
#if DEBUG
        Error.WriteLine($"^^^ LOG[{line}] ^^^");
        xs.Iter(x => Error.WriteLine(x));
        Error.WriteLine($"vvv LOG[{line}] vvv\n");
#endif
    }
    public static void Log<T>(this T[,] xs, [CallerLineNumber] int line = 0)
    {
#if DEBUG
        Error.WriteLine($"^^^ LOG[{line}] ^^^");
        xs.GetLength(0).Rep(i =>
        {
            xs.GetLength(1).Rep(j => Error.Write($"{xs[i, j]} "));
            Error.WriteLine();
        });
        Error.WriteLine($"vvv LOG[{line}] vvv\n");
#endif
    }
    public static string Reversed(this string s) => string.Join("", s.Reverse());
    public static string Repeat(this string s, int n) => string.Concat(Enumerable.Repeat(s, n));
    #endregion
}