#include <iostream>
#include <algorithm>
#include <iomanip>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <numeric>
#include <bitset>
#include <cmath>

#pragma GCC optimize ("O3")
static const int MOD = 1000000007;
using ll = long long;
using u32 = uint32_t;
using namespace std;

template<class T> constexpr T INF = ::numeric_limits<T>::max()/32*15+208;

#include <random>
template< class T>
T pow_ (T x, uint64_t n, uint64_t M){
    T u = 1;
    if(n > 0){
        u = pow_(x, n/2, M);
        if (n % 2 == 0) u = (u*u) % M;
        else u = (((u * u)% M) * x) % M;
    }
    return u;
};

bool suspect(__uint128_t a, uint64_t s, uint64_t d, uint64_t n){
    __uint128_t x = pow_(a, d, n);
    if (x == 1) return true;
    for (int r = 0; r < s; ++r) {
        if(x == n-1) return true;
        x = x * x % n;
    }
    return false;
}

template<class T>
bool miller_rabin(T m){
    uint64_t n = m;
    if (n <= 1 || (n > 2 && n % 2 == 0)) return false;
    uint64_t d = n - 1, s = 0;
    while (!(d&1)) {++s; d >>= 1;}
    vector<uint64_t> v = {2, 325, 9375, 28178, 450775, 9780504, 1795265022};
    if(n <= 4759123141LL) v = {2, 7, 61};
    for (auto &&p : v) {
        if(p >= n) break;
        if(!suspect(p, s, d, n)) return false;
    }
    return true;
}
constexpr int M = 12000;
struct Prime { // Wheel factorization
    static constexpr int wheel[] = {4, 2, 4, 2, 4, 6, 2, 6},
            wheel2[] = {7, 11, 13, 17, 19, 23, 29, 31},
            wheel_sum[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7};
    static inline int f(int n){ return (n-1)/30*8 + wheel_sum[(n-1)%30]; }
    static inline int g(int n){ return ((n-1) >> 3)*30 + wheel2[(n-1)&7]; }
    vector<int> primes;

    Prime(int M) {
        primes = {2, 3, 5};
        if(M < 7){
            while(!primes.empty() && M < primes.back()) primes.pop_back();
            return;
        }
        int n = f(M), m = g(n), k = f(int(floor(sqrt(M))));
        primes.reserve(3+max(0, (int)(n/(log(n)-1.12))));
        vector<bool> sieve(n+1, true);
        for (int i = 1; i <= k; ++i) {
            if(sieve[i]){
                ll p = g(i), q = p*p;
                int j = (i-1)&7;
                while(q <= m){
                    sieve[f(q)] = false;
                    q += wheel[j] * p;
                    j = (j+1)&7;
                }
            }
        }
        for (int i = 1; i <= n; ++i) {
            if(sieve[i]) primes.emplace_back(g(i));
        }
    }
};
constexpr int Prime::wheel[], Prime::wheel2[], Prime::wheel_sum[];

Prime P(M);

random_device rng;
template<class T>
T pollard_rho2(T n) {
    uniform_int_distribution<T> ra(1, n-1);
    while(true){
        T c = ra(rng), g = 1, r = 1, y = ra(rng),m = 2100,
                ys = 0, q = 1, xx = 0;
        while(c == n-2) c = ra(rng);
        while(g == 1){
            xx = y;
            for (int i = 1; i <= r; ++i) {
                y = static_cast<T>(((__uint128_t)y * y) % n);
                y = static_cast<T>((__uint128_t)y + c) % n;
            }
            T k = 0; g = 1;
            while(k < r && g == 1){
                for (int i = 1; i <= (m > (r-k) ? (r-k) : m); ++i) {
                    ys = y;
                    y = static_cast<T>(((__uint128_t)y * y) % n);
                    y = static_cast<T>((__uint128_t)y + c) % n;
                    q = static_cast<T>(((__uint128_t)q * (xx > y ? xx - y : y - xx)) % n);
                }
                g = __gcd(q, n);
                k += m;
            }
            r *= 2;
        }
        if(g == n) g = 1;
        while (g == 1){
            ys = static_cast<T>(((__uint128_t)ys * ys) % n);
            ys = static_cast<T>((__uint128_t)ys + c) % n;
            g = __gcd(xx > ys ? xx - ys : ys - xx, n);
        }
        if (g != n && miller_rabin(g)) return g;
    }
}

template<class T>
vector<T> prime_factor(T n, int d = 0){
    vector<T> a, res;
    if(!d) for (auto &&i : P.primes) {
            while (n % i == 0){
                res.emplace_back(i);
                n /= i;
            }
        }
    while(n != 1){
        if(miller_rabin(n)){
            a.emplace_back(n);
            break;
        }
        T x = pollard_rho2(n);
        n /= x;
        a.emplace_back(x);
    }
    for (auto &&i : a) {
        if (miller_rabin(i)) {
            res.emplace_back(i);
        } else {
            vector<T> b = prime_factor(i, d + 1);
            for (auto &&j : b) res.emplace_back(j);
        }
    }
    return res;
}
int table[] = {0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
int main() {
    ll n;
    cin >> n;
    if(n == 1){
        puts("0");
        return 0;
    }
    auto p = prime_factor(n);
    sort(p.begin(),p.end());
    vector<pair<ll, int>> a;
    a.reserve(100);
    a.emplace_back(p[0], 1);
    for (int i = 1; i < p.size(); ++i) {
        if(p[i] == a.back().first){
            a.back().second++;
        }else {
            a.emplace_back(p[i], 1);
        }
    }
    int ans = 0;
    for (auto &&j : a) {
        ans += table[j.second];
    }
    cout << ans << "\n";
    return 0;
}


#include<bits/stdc++.h>
using namespace std ;

// Template START
#define endl "\n"
#define async ios_base::sync_with_stdio(false); cin.tie(NULL);
#define int long long int
#define all(y) y.begin(), y.end()
#define present( x, y ) (x.find( y ) != x.end())
const int mod = (int)1e9 + 7 ;
template<class T>
auto matrix( int r, int c, T v ){
    return vector<vector<T>>( r, vector<T>( c, v ) ) ;
}
template<class T>
auto matrix( int o1, int o2, int o3, T v ){
    return vector<vector<vector<T>>>( o1, vector<vector<T>>( o2, vector<T>( o3, v ) ) ) ;
}
#define v vector
int power( int x, int n ){
    if( n == 0 ) return 1 ;
    else if( n & 1 ) return ( x * power( (x*x) % mod, n / 2 ) ) % mod ;
    return power( (x*x) % mod, n / 2 ) % mod ;
}
template<class T> void __print( v<T> &arr ){
    int n = arr.size() ;
    cerr << "[ " ;
    for( int i = 0 ; i < n ; i++ ) {
        cerr << arr[i] ;
        if( i != n - 1 ) cerr << ", " ;
    }
    cerr << " ]" << endl ;
}
template<class T> void __print( T arr[], int n ){
    cerr << "[ " ;
    for( int i = 0 ; i < n ; i++ ) {
        cerr << arr[i] ;
        if( i != n - 1 ) cerr << ", " ;
    }
    cerr << " ]" << endl ;
}
#define print(x) cerr << "{ " << #x << " : " << x << " } " ;
#define println(x) cerr << "{ " << #x << " : " << x << " }" << endl ;
// Template END
int solve( int n ){
    int cnt = 0 ;
    for( int i = 2 ; i * i <= n ; i++ ){
        if( n % i == 0 ) ++cnt ;
        while( n % i == 0 ){
            n /= i ;
        }
    }
    if( n > 2 ) ++cnt ;
    return cnt ;
}

signed main(){
    int n ; cin >> n ;
    cout << solve(n) << endl ;
    return 0 ;
}


#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
#include<cstdlib>
#include<set>
#include<math.h>
#include<map>
#include<unordered_map>
#include<iomanip>
#include<queue>

using namespace std;
using ll = long long;
using ull = unsigned long long;
ll amari = 1000000007;
#define rep(n,x) for(ll i=0;i<n;i++) cin>>x[i];
#define forr(a,b) for(ll i=a;i<b;i++);
ll modpow(ll a, ll n, ll mod)
{
	ll res = 1;
	while (0 < n)
	{
		if (n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res;
}
ll gcd(ll x, ll y)
{
	if (x % y == 0) return y;
	else return gcd(y, x % y);
}
// 1or素数だと１を返す
ll prime(ll x)
{
	for (ll i = 2; i * i <= x; i++)
	{
		if (x % i == 0) return 0;
	}
	return 1;
}

int main()
{
	ll n;
	cin >> n;
	ll k = n;
	ll x = sqrt(n);
	vector<ll> a(x+10, 0);

	for (ll i = 2; i < x + 5; i++)
	{
		while (k % i == 0)
		{
			a[i]++;
			k /= i;
		}
	}

	ll ans = 0;
	ll y = 0;
	for (ll i = 0; i < x+5; i++)
	{
		if (a[i] != 0)
		{
			y = 0;
			while (y * (y + 1) <= 2 * a[i])
			{
				y++;
			}
			y--;
			ans += y;
		}
	}
if(prime(n)==1) ans=1;
  if(n==1) ans=0;
	cout << ans << "\n";

	return 0;
}


#include <iostream>
#include <cstring>
#include<vector>
#include <algorithm>
#include<cstdlib>
#include<set>
#include<math.h>
#include<map>
#include<unordered_map>
#include<iomanip>
#include<queue>

using namespace std;
using ll = long long;
using ull = unsigned long long;
ll amari = 1000000007;
#define rep(n,x) for(ll i=0;i<n;i++) cin>>x[i];
#define forr(a,b) for(ll i=a;i<b;i++);
ll modpow(ll a, ll n, ll mod)
{
	ll res = 1;
	while (0 < n)
	{
		if (n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res;
}
ll gcd(ll x, ll y)
{
	if (x % y == 0) return y;
	else return gcd(y, x % y);
}
// 1or素数だと１を返す
ll prime(ll x)
{
	for (ll i = 2; i * i <= x; i++)
	{
		if (x % i == 0) return 0;
	}
	return 1;
}

int main()
{
	ll n;
	cin >> n;
	ll k = n;
	ll x = sqrt(n);
	vector<ll> a(x+10, 0);

	for (ll i = 2; i < x + 5; i++)
	{
		while (k % i == 0)
		{
			a[i]++;
			k /= i;
		}
	}

	ll ans = 0;
	ll y = 0;
	for (ll i = 0; i < x+5; i++)
	{
		if (a[i] != 0)
		{
			y = 0;
			while (y * (y + 1) <= 2 * a[i])
			{
				y++;
			}
			y--;
			ans += y;
		}
	}
	if (n == 1) ans = 0;

	cout << ans << "\n";

	return 0;
}


//div game
#include <stdio.h>
#include <math.h>

int main(void){
    unsigned long int n;
    unsigned long int sq_n;
    unsigned int i=2;
    unsigned long int cnt = 0;
    unsigned long int div;

    scanf("%lu",&n);
    sq_n = sqrt(n);

    if(n%i==0) {//i=2
        div = i;
        while(n%div==0){
            n/= div;
            div *= i;
            cnt ++;
        }
        while(n%i == 0) n/=i;
    }

    for(i = 3;i<=sq_n;i+=2){
        if(n%i==0) {
            div = i;
            while(n%div==0){
                n/= div;
                div *= i;
                cnt ++;
            }
            while(n%i == 0) n/=i;
        }
    }
    if(n != 1) cnt ++;
    printf("%lu",cnt);

    return 0;
}


//div game
#include <stdio.h>
#include <math.h>

int main(void){
    unsigned long int n;

    scanf("%lu",&n);

    unsigned int i=2;
    unsigned long int cnt = 0;

    if(n%i==0) {
        unsigned long int div = i;
        for(unsigned int j = 1;n%(int)pow(div,j)==0;j++){
            n/= pow(div,j);
            cnt ++;
        }
        while(n%div == 0) n/=div;
    }

    for(i = 3;i<sqrt(n);i+=2){
        if(n%i==0) {
            unsigned long int div = i;
            for(unsigned int j = 1;n%(int)pow(div,j)==0;j++){
                n/= pow(div,j);
                cnt ++;
            }
            while(n%div == 0) n/=div;
        }
    }
    if(n>sqrt(n)) cnt ++;
    printf("%lu",cnt);

    return 0;
}


#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <math.h>
#ifdef __cplusplus
#include <bits/stdc++.h>
#endif

int32_t nextint(void){ char c=getchar_unlocked(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar_unlocked(); bool s=false; if(c=='-'){s=true;c=getchar_unlocked();} uint32_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar_unlocked(); } return s?-x:x; }
int64_t nextlong(void){ char c=getchar_unlocked(); while(c!='-'&&(c<'0'||'9'<c)) c=getchar_unlocked(); int s=0; if(c=='-'){s=1;c=getchar_unlocked();} uint64_t x=0; while('0'<=c && c<='9'){ x=x*10+c-'0'; c=getchar_unlocked(); } return s?-x:x; }

int a[40]={0,1,1,2,2,2,3,3,3,3,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8};
int main(void){
	long n=nextlong();
	int ans=0;
	{int i=2; int b=0; while(n%i==0){ n/=i; b++; } ans+=a[b];}
	{int i=3; int b=0; while(n%i==0){ n/=i; b++; } ans+=a[b];}
	{int i=5; int b=0; while(n%i==0){ n/=i; b++; } ans+=a[b];}
	int m=sqrt(n);
	for(int i=7; i<m;){
		{int b=0; while(n%i==0){ n/=i; b++; } ans+=a[b];}
		i+=4;
		{int b=0; while(n%i==0){ n/=i; b++; } ans+=a[b];}
		i+=2;
	}
	printf("%d\n", ans+(n>1));
}


#include<bits/stdc++.h>
using namespace std;
using ll=long long int;
int main()
{
    map<int,int> m;
    long long int n;
    cin>>n;
    for(int i=2;i<=sqrt(n);i++)
    {
        while(n%i==0)
        {
            m[i]++;
            n=n/i;
        }
    }
    if(n>1)
    m[n]++;
    int ans=0;
    for(auto it:m)
    {
        int p=it.second;
        int curr=1;
        while(p>=curr)
        {
            ans++;
            p-=curr;
            curr++;
        }
    }
    cout<<ans<<endl;

}


#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
	long long n,ans=0,total,j,i;
	scanf("%lld",&n);
	for(i=2;i<=sqrt(n)||n==1;i++){
		if(n%i==0){
			total=0,j=1;
			while(n%i==0){
				n/=i;
				total++;
			}
			while(total-j>=0){
				total-=j;
				j++;ans++;
			}
		}
	}
	if(n!=1)ans++;
	printf("%lld\n",ans);
}


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define ll long long

void swap (int *x, int *y) {
  int temp;

  temp = *x;
  *x = *y;
  *y = temp;

  return;
}

int gcd(int a, int b){
  int c;

  while (b > 0){
    c = a % b;
    a = b;
    b = c;
  }

  return a;
}

int upll(const void*a, const void*b){
  return*(ll*)a<*(ll*)b?-1:*(ll*)a>*(ll*)b?1:0;
}

int downll(const void*a, const void*b){
  return*(ll*)a<*(ll*)b?1:*(ll*)a>*(ll*)b?-1:0;
}

void sortup(ll*a,int n){
  qsort(a,n,sizeof(ll),upll);
}

void sortdown(ll*a,int n){
  qsort(a,n,sizeof(ll),downll);
}

long int modpow(long int a,long int n,long int mod){
  long int ans=1;
  while(n>0){
    if(n & 1){
      ans=ans*a%mod;
    }
    a=a*a%mod;
    n/=2;
  }
  return ans;
}

long int modinv(long int a,long int mod){
  return modpow(a,mod-2,mod);
}

int max(int a,int b){
  if(a<b){
    return b;
  }
  else{
    return a;
  }
}

int min(int a,int b){
  if(a<b){
    return a;
  }
  else{
    return b;
  }
}

void chmax(int *a,int b){
  if(*a < b){
    *a = b;
  }

  return;
}

void chmin(int *a,int b){
  if(*a > b){
    *a =b;
  }

  return;
}

/****************************************\
| Thank you for viewing my code:)        |
| Written by RedSpica a.k.a. RanseMirage |
| Twitter:@asakaakasaka                  |
\****************************************/

int main(void){
  long int n;
  scanf("%ld",&n);
  long int N=n;
  int ans=0;

  for(int i=2;i*i<=N;i++){
    int cnt=0;
    while(n%i==0){
      cnt++;
      n/=i;
    }

    for(int j=1;j<100;j++){
      if(cnt<j*(j+1)/2){
        ans+=j-1;
        break;
      }
    }
  }
  if(n!=1){
    ans++;
  }

  printf("%d\n",ans);

  return 0;
}


// inputに入力データ全体が入る
function Main(input) {
  n = parseInt(input);
  var priArray = getPrimeFactors(n);
  var summary = [];
  var tmp = 0 ;
  for (let i=0;i<priArray.length;i++){
    if (priArray[i] == tmp){
      summary[summary.length - 1] ++;
    }else{
      summary.push(1);
      tmp = priArray[i];
    }
  }
  var sum = 0
  for (let i=0;i<summary.length;i++){
    var ok = 1;
    var cnt = 1;
    while (ok === 1){
      if (cnt * (cnt+1) / 2 > summary[i]){
        ok = 0;
        sum += cnt -1;
      }else{
        cnt ++;
      }
    }
  }
  console.log(sum);
}

const getPrimeFactors = n => {
  if (n < 2) return [];
  if (n === 2 || n === 3 || n === 5) return [n];
  if (n % 2 === 0) return [2, ...getPrimeFactors(n/2)];
  if (n % 3 === 0) return [3, ...getPrimeFactors(n/3)];
  if (n % 5 === 0) return [5, ...getPrimeFactors(n/5)];
  let prime = 7;
  let step = 4;
  const limit = Math.sqrt(n);
  while (prime <= limit) {
    if (n % prime === 0) return [prime, ...getPrimeFactors(n/prime)];
    prime += step;
    step = 6 - step;
  }
  return [n];
}

Main(require("fs").readFileSync("/dev/stdin","utf8"));


const input = require("fs").readFileSync("/dev/stdin", "utf8")
const N = parseInt(input, 10)

let c = 0
let n = N
for (let i = 2; i * i < n; i++) {
    let _i = i
    while (n % _i === 0) {
        n /= _i
        c++
        _i = _i * i
    }
    while (n % i === 0) {
        n /= i
    }
}

if (n > 1) {
    c++
}
console.log(c)


"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  var n = next();
  var map = {};
  var k = n;
  for(var i = 2; i*i <= k; i++){
    if(k % i === 0){
      map[i] = 0;
      while(k % i === 0)map[i]++,k /= i;
    }
  }
  if(k > 1)map[k] = 1;
  var a = [];
  for(var i in map)a.push(map[i]);
  var ans = 0;
  a.sort((a,b) => b-a);
  for(var i = 0; i < a.length; i++){
    for(var j = 1; j <= a[i]; j++){
      ans++;
      a[i] -= j;
    }
  }
  return ans;
}


function Main(input){
    input=input.split("\n");  //ここまで必須
    var result=0;
    var num=input[0];
    for (i=2;i<parseInt(input[0])+1;i++){
       if (parseInt(num)%parseInt(i)==0){
           result=result+1;
           num=parseInt(num)/parseInt(i)
       }
    }
    console.log(result)
}
Main(require("fs").readFileSync("/dev/stdin","utf8"));


function Main(input) {
	input = input.trim();
	var N = parseInt(input, 10);
	var vec_p = [];
	var vec_e = [];
	var tmpN = N;
	var j = 0;
	var k = 0;
	var ans = 0;
	var checkTmpN = 1;
	var tmp;
	for (var i = 2; i <= Math.sqrt(N); i++){
		j = 0;
		same_number:
		while (true) {
			if (tmpN % i === 0){
				j ++;
				tmpN = tmpN / i ;
				checkTmpN *= i;
				if (j === 1) {
					vec_p.push(i);
					vec_e.push(1);
					k++;
				} else {
					vec_e[k - 1] ++;
				}
			} else {
				break same_number;
			}
		}
	}
	if (checkTmpN !== N) {
		vec_p.push(N / checkTmpN);
		vec_e.push(1);
	}
	for (var i = 0; i < vec_e.length; i++){
		tmp = Math.floor((Math.sqrt(1 + (8 * vec_e[i])) - 1) / 2);
		ans += tmp;
	}
 	console.log(ans,vec_p,vec_e);
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));


function Main(input) {
	input = input.trim().split(" ");
	var N = parseInt(input, 10);
	var vec_p = [];
	var vec_e = [];
	var tmpN = N;
	var j = 0;
	var k = 0;
	var  ans = 0;
	var tmp;
	for (var i = 2; i <= Math.sqrt(N); i++){
		j = 0;
		same_number:
		while (true) {
			if (tmpN % i === 0){
				j ++;
				tmpN = tmpN / i ;
				if (j === 1) {
					vec_p.push(i);
					vec_e.push(1);
					k++;
				} else {
					vec_e[k - 1] ++;
				}
			} else {
				break same_number;
			}
		}
	}
	for (var i = 0; i < vec_e.length; i++){
		tmp = Math.floor((Math.sqrt(1 + (8 * vec_e[i])) - 1) / 2);
		ans += tmp;
	}
  	if ((N !== 1) && (ans === 0)) ans = 1;
 	console.log(ans);
}

Main(require("fs").readFileSync("/dev/stdin", "utf8"));


package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
	"sort"
	"strconv"
)

var MaxN int

func main() {
	sc := NewScanner()

	MaxN = Pow(10, 12)

	n := sc.ReadInt()

	ans := 0
	primeCounts := PrimeFactorize(n)
	for _, count := range primeCounts {
		ans += f(count)
	}

	fmt.Println(ans)
}

func f(n int) int {
	switch {
	case n < 1:
		return 0
	case n < 3:
		return 1
	case n < 6:
		return 2
	case n < 10:
		return 3
	case n < 15:
		return 4
	case n < 21:
		return 5
	case n < 28:
		return 6
	case n < 36:
		return 7
	case n < 45:
		return 8
	}
	return -1
}

func PrimeFactorize(n int) map[int]int {
	primeCounts := make(map[int]int)

	sqrtMax := int(math.Sqrt(float64(MaxN)))

	for n%2 == 0 {
		primeCounts[2]++
		n /= 2
	}
	for n%3 == 0 {
		primeCounts[3]++
		n /= 3
	}

	flag := true
	for i := 5; n > 1 && i <= sqrtMax; {
		for n%i == 0 {
			primeCounts[i]++
			n /= i
		}

		if flag {
			i += 2
		} else {
			i += 4
		}
		flag = !flag
	}

	if n > 1 {
		primeCounts[n]++
	}

	return primeCounts
}

// util
// *   math/simple

func Abs(x int) int {
	if x >= 0 {
		return x
	}
	return -x
}

func Min(values ...int) int {
	if len(values) == 0 {
		panic("no values")
	}
	min := values[0]
	for _, v := range values {
		if v < min {
			min = v
		}
	}
	return min
}

func Max(values ...int) int {
	if len(values) == 0 {
		panic("no values")
	}
	max := values[0]
	for _, v := range values {
		if v > max {
			max = v
		}
	}
	return max
}

func Pow(base int, exponent uint) int {
	answer := 1
	for i := uint(0); i < exponent; i++ {
		answer *= base
	}
	return answer
}

func Ceil(divident, dividor int) int {
	quo := divident / dividor
	rem := divident % dividor

	if rem != 0 {
		if (divident > 0 && dividor > 0) ||
			(divident < 0 && dividor < 0) {
			return quo + 1
		}
	}
	return quo
}

// *   sortutil

func ReverseInts(a []int) {
	sort.Sort(sort.Reverse(sort.IntSlice(a)))
}

func ReverseStrings(a []string) {
	sort.Sort(sort.Reverse(sort.StringSlice(a)))
}

// *   io

type Scanner struct {
	bufScanner *bufio.Scanner
}

func NewScanner() *Scanner {
	bufSc := bufio.NewScanner(os.Stdin)
	bufSc.Split(bufio.ScanWords)
	bufSc.Buffer(nil, 100000000)
	return &Scanner{bufSc}
}

func (sc *Scanner) ReadString() string {
	bufSc := sc.bufScanner
	bufSc.Scan()
	return bufSc.Text()
}

func (sc *Scanner) ReadInt() int {
	bufSc := sc.bufScanner
	bufSc.Scan()
	text := bufSc.Text()

	num, err := strconv.Atoi(text)
	if err != nil {
		panic(err)
	}
	return num
}

func (sc *Scanner) ReadFloat() float64 {
	bufSc := sc.bufScanner
	bufSc.Scan()
	text := bufSc.Text()

	num, err := strconv.ParseFloat(text, 64)
	if err != nil {
		panic(err)
	}
	return num
}


package main

import "fmt"

func main() {
	var n int
	fmt.Scan(&n)

	count := 0
	for _, cnt := range PrimeFactorize(n) {
		for i := 1; i <= cnt; i++ {
			count++
			cnt -= i
		}
	}

	fmt.Println(count)
}

// generated by https://github.com/murosan/gollect

func PrimeFactorize(n int) map[int]int {
	m := make(map[int]int)
	for n%2 == 0 {
		m[2]++
		n /= 2
	}
	for i := 3; i*i <= n; i += 2 {
		for n%i == 0 {
			m[i]++
			n /= i
		}
	}
	if n != 1 {
		m[n]++
	}
	return m
}


package main

import "fmt"

func main() {
	var n int
	fmt.Scanf("%d", &n)

	factors := factorize(n)
	count := 0
	for _, pair := range factors {
		i := 1
		for pair[1] >= i {
			pair[1] -= i
			i++
			count++
		}
	}

	fmt.Printf("%d\n", count)
}

func factorize(n int) [][]int {
	tmp := n
	factors := [][]int{}
	for f := 2; f*f <= n; f++ {
		i := 0
		for tmp%f == 0 {
			i++
			tmp /= f
		}
		if i > 0 {
			factors = append(factors, []int{f, i})
		}
	}
	if n > 1 && len(factors) == 0 {
		factors = append(factors, []int{n, 1})
	}
	return factors
}


package main

import "fmt"

func main() {
	var n int64
	fmt.Scan(&n)
	m := make(map[int64]bool)
	for i := int64(2); i*i <= n; i++ {
		if n%i == 0 && !m[i] {
			n /= i
			m[i] = true
		}
	}
	if n != 1 && !m[n] {
		m[n] = true
	}
	fmt.Println(len(m))
}


package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
)

func main() {
	scanner := NewScanner()
	n := scanner.NextInt64()
	if n == 1 {
		fmt.Println(0)
		return
	}
	r := 1
	for ; int64(r*r) <= n; r++ {
	}
	ms := make([]bool, r)
	count := 0
	for i := 2; i < len(ms); i++ {
		if ms[i] {
			continue
		}
		for j := 1; i*j < len(ms); j++ {
			ms[i*j] = true
		}
		for j := i; j < len(ms); j *= i {
			if n%int64(j) == 0 {
				n /= int64(j)
				count++
			}
		}
	}
	if count == 0 {
		// Nは素数
		fmt.Println(1)
	} else {
		fmt.Println(count)
	}
}

type Scanner struct {
	scanner *bufio.Scanner
}

func NewScanner() *Scanner {
	s := bufio.NewScanner(os.Stdin)
	s.Split(bufio.ScanWords)
	return &Scanner{s}
}

func (s *Scanner) NextWord() string {
	if !s.scanner.Scan() {
		log.Fatal("failed to find the next word")
	}
	return s.scanner.Text()
}

func (s *Scanner) NextInt() int {
	str := s.NextWord()
	i, err := strconv.Atoi(str)
	if err != nil {
		log.Fatalf("failed to parse %s to int", str)
	}
	return i
}

func (s *Scanner) NextInt64() int64 {
	str := s.NextWord()
	i, err := strconv.ParseInt(str, 10, 64)
	if err != nil {
		log.Fatalf("failed to parse %s to int64", str)
	}
	return i
}


p`factor`.split.tally.sum{((8*_2+1)**0.5-1).to_i/2}-1


p`factor`.split.tally.sum{|_,v|(0..).find{0>v+=~_1}}-1


p~`factor`.split.tally.sum{1-((2*_2+2)**0.5).round}


require "prime"
#input of int(split by space)
def get_i()
  return gets.chomp.split(" ").map(&:to_i)
end
#input of float(split by space)
def get_f()
  return gets.chomp.split(" ").map(&:to_f)
end
#input of string(split by space)
def get()
  return gets.chomp.split(" ")
end
#input of string(split per one character)
def get_nsp()
  return gets.chomp.split("")
end
#yes or no decision
def yn_judge(bool,y="Yes",n="No")
  return bool ? y : n
end
#create of array
def array(size1,init=nil,size2=-1)
  if size2==-1
      return Array.new(size1){init}
  else
      return Array.new(size2){Array.new(size1){init}}
  end
end

def max(a,b)
    return a>b ? a : b
end

def min(a,b)
    return a>b ? b : a
end

INF=Float::INFINITY

N=gets.to_i
if N==1
    puts 0
    exit
elsif Prime.prime?(N)
    puts 1
    exit
end
n=N
table=Hash.new(false)
table[1]=true
ans=0
2.upto((N**0.5).to_i) do|i|
  k=i
  while not table[k] and (n%k).zero?
    n/=k
    table[k]=true
    k*=i
    ans+=1
  end
end
puts ans


require "prime"
#input of int(split by space)
def get_i()
  return gets.chomp.split(" ").map(&:to_i)
end
#input of float(split by space)
def get_f()
  return gets.chomp.split(" ").map(&:to_f)
end
#input of string(split by space)
def get()
  return gets.chomp.split(" ")
end
#input of string(split per one character)
def get_nsp()
  return gets.chomp.split("")
end
#yes or no decision
def yn_judge(bool,y="Yes",n="No")
  return bool ? y : n
end
#create of array
def array(size1,init=nil,size2=-1)
  if size2==-1
      return Array.new(size1){init}
  else
      return Array.new(size2){Array.new(size1){init}}
  end
end

def max(a,b)
    return a>b ? a : b
end

def min(a,b)
    return a>b ? b : a
end

INF=Float::INFINITY

N=gets.to_i
if N==1
    puts 0
    exit
elsif Prime.prime?(N)
    puts 1
    exit
end
n=N
table=Hash.new(false)
table[1]=true
ans=0
2.upto((N**0.5).to_i) do|i|
  k=i
  while not table[k] and (n%k).zero?
    n/=k
    table[k]=true
    k+=i
    ans+=1
  end
end
puts ans


require "prime"
#input of int(split by space)
def get_i()
  return gets.chomp.split(" ").map(&:to_i)
end
#input of float(split by space)
def get_f()
  return gets.chomp.split(" ").map(&:to_f)
end
#input of string(split by space)
def get()
  return gets.chomp.split(" ")
end
#input of string(split per one character)
def get_nsp()
  return gets.chomp.split("")
end
#yes or no decision
def yn_judge(bool,y="Yes",n="No")
  return bool ? y : n
end
#create of array
def array(size1,init=nil,size2=-1)
  if size2==-1
      return Array.new(size1){init}
  else
      return Array.new(size2){Array.new(size1){init}}
  end
end

def max(a,b)
    return a>b ? a : b
end

def min(a,b)
    return a>b ? b : a
end

INF=Float::INFINITY

N=gets.to_i
if N==1
    puts 0
    exit
elsif Prime.prime?(N)
    puts 1
    exit
end
n=N
table=array((N**0.5)+1,false)
table[1]=true
ans=0
2.upto((N**0.5).to_i) do|i|
  k=i
  while not table[k] and (n%k).zero?
    n/=k
    table[k]=true
    k+=i
    ans+=1
  end
end
puts ans


#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
use std::io::{Write, BufWriter};
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8
macro_rules! input {
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r|r.unwrap() as char)
                .skip_while(|c|c.is_whitespace())
                .take_while(|c|!c.is_whitespace())
                .collect()
        };
        input_inner!{next, $($r)*}
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};

    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{$next $($r)*}
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt),* )) => {
        ( $(read_value!($next, $t)),* )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, [ $t:tt ]) => {{
        let len = read_value!($next, usize);
        (0..len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    }};

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Parse error")
    };
}

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

/// https://judge.yosupo.jp/submission/5155
mod pollard_rho {
    use std::collections::HashMap;
    /// binary gcd
    pub fn gcd(mut x: i64, mut y: i64) -> i64 {
        if y == 0 { return x; }
        if x == 0 { return y; }
        let k = (x | y).trailing_zeros();
        y >>= k;
        x >>= x.trailing_zeros();
        while y != 0 {
            y >>= y.trailing_zeros();
            if x > y { let t = x; x = y; y = t; }
            y -= x;
        }
        x << k
    }

    fn add_mod(x: i64, y: i64, n: i64) -> i64 {
        let z = x + y;
        if z >= n { z - n } else { z }
    }

    fn mul_mod(x: i64, mut y: i64, n: i64) -> i64 {
        assert!(x >= 0);
        assert!(x < n);
        let mut sum = 0;
        let mut cur = x;
        while y > 0 {
            if (y & 1) == 1 {
                sum = add_mod(sum, cur, n);
            }
            cur = add_mod(cur, cur, n);
            y >>= 1;
        }
        sum
    }

    fn mod_pow(x: i64, mut e: i64, n: i64) -> i64 {
        let mut prod = if n == 1 { 0 } else { 1 };
        let mut cur = x % n;
        while e > 0 {
            if (e & 1) == 1 {
                prod = mul_mod(prod, cur, n);
            }
            e >>= 1;
            if e > 0 {
                cur = mul_mod(cur, cur, n);
            }
        }
        prod
    }

    pub fn is_prime(n: i64) -> bool {
        if n <= 1 { return false; }
        let small = [2, 3, 5, 7, 11, 13];
        if small.iter().any(|&u| u == n) { return true; }
        if small.iter().any(|&u| n % u == 0) { return false; }
        let mut d = n - 1;
        let e = d.trailing_zeros();
        d >>= e;
        // https://miller-rabin.appspot.com/
        let a = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
        a.iter().all(|&a| {
            if a % n == 0 { return true; }
            let mut x = mod_pow(a, d, n);
            if x == 1 { return true; }
            for _ in 0 .. e {
                if x == n - 1 {
                    return true;
                }
                x = mul_mod(x, x, n);
                if x == 1 { return false; }
            }
            x == 1
        })
    }

    fn pollard_rho(n: i64, c: &mut i64) -> i64 {
        // An improvement with Brent's cycle detection algorithm is performed.
        // https://maths-people.anu.edu.au/~brent/pub/pub051.html
        if n % 2 == 0 { return 2; }
        loop {
            let mut x: i64; // tortoise
            let mut y = 2; // hare
            let mut d = 1;
            let cc = *c;
            let f = |i| add_mod(mul_mod(i, i, n), cc, n);
            let mut r = 1;
            // We don't perform the gcd-once-in-a-while optimization
            // because the plain gcd-every-time algorithm appears to
            // outperform, at least on judge.yosupo.jp :)
            while d == 1 {
                x = y;
                for _ in 0..r {
                    y = f(y);
                    d = gcd((x - y).abs(), n);
                    if d != 1 {
                        break;
                    }
                }
                r *= 2;
            }
            if d == n {
                *c += 1;
                continue;
            }
            return d;
        }
    }

    /// Outputs (p, e) in p's ascending order.
    pub fn factorize(x: i64) -> Vec<(i64, usize)> {
        if x <= 1 {
            return Vec::new();
        }
        let mut hm = HashMap::new();
        let mut pool = vec![x];
        let mut c = 1;
        while let Some(u) = pool.pop() {
            if is_prime(u) {
                *hm.entry(u).or_insert(0) += 1;
                continue;
            }
            let p = pollard_rho(u, &mut c);
            pool.push(p);
            pool.push(u / p);
        }
        let mut v: Vec<_> = hm.into_iter().collect();
        v.sort();
        v
    }
} // mod pollard_rho

use pollard_rho::*;

fn solve() {
    let out = std::io::stdout();
    let mut out = BufWriter::new(out.lock());
    macro_rules! puts {
        ($($format:tt)*) => (let _ = write!(out,$($format)*););
    }
    input!(n: i64);
    let pe = factorize(n);
    let mut tot = 0;
    for (_p, e) in pe {
        let mut k = 0;
        while k * (k + 1) / 2 <= e {
            k += 1;
        }
        k -= 1;
        tot += k;
    }
    puts!("{}\n", tot);
}

fn main() {
    // In order to avoid potential stack overflow, spawn a new thread.
    let stack_size = 104_857_600; // 100 MB
    let thd = std::thread::Builder::new().stack_size(stack_size);
    thd.spawn(|| solve()).unwrap().join().unwrap();
}


use proconio::input;

fn main() {
    input! {
        mut n: u64,
    }
    let mut v = vec![];
    calc(n, &mut v);

    let mut r = 0;
    for e in v {
        r += get_count(e);
    }

    println!("{}", r);
}

fn calc(n: u64, v: &mut Vec<u64>) {
    let sub = |n: u64, m: u64| -> (u64, u64) {
        let mut c = 0;
        let mut r = n;
        while r % m == 0 {
            c += 1;
            r /= m;
        }
        (c, r)
    };

    let (c, n) = sub(n, 2);
    if c > 0 {
        v.push(c);
    }
    let mut m = 3;
    let mut r = n;
    while m * m <= r {
        let (c, n) = sub(r, m);
        if c > 0 {
            v.push(c);
        }
        r = n;
        m += 2;
    }
    if r > 1 {
        v.push(1);
    }
}

fn get_count(n: u64) -> u64 {
    if n <= 2 {
        1
    } else if n <= 2 + 3 {
        2
    } else if n <= 2 + 3 + 4 {
        3
    } else if n <= 2 + 3 + 4 + 5 {
        4
    } else if n <= 2 + 3 + 4 + 5 + 6 {
        5
    } else if n <= 2 + 3 + 4 + 5 + 6 + 7 {
        6
    } else if n <= 2 + 3 + 4 + 5 + 6 + 7 + 8 {
        7
    } else if n <= 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 {
        8
    } else {
        9
    }
}


#[allow(unused)]
use proconio::marker::*;
use proconio::{fastout, input};
#[allow(unused)]
use std::cmp::{max, min};
#[allow(unused)]
use std::collections::{HashMap, HashSet, VecDeque};

#[fastout]
fn main() {
    input! {
        n: i64,
    }
    let mut rec = vec![];
    factorization(n, &mut rec);

    let mut ans = 0;
    for r in rec {
        ans += help(r);
    }
    println!("{}", ans);
}

fn factorization(n: i64, rec: &mut Vec<i64>) {
    fn factor_sub(n: i64, m: i64) -> (i64, i64) {
        let mut c = 0;
        let mut x = n;
        while x % m == 0 {
            c += 1;
            x /= m;
        }
        (c, x)
    }

    let (c, n) = factor_sub(n, 2);
    if c > 0 {
        rec.push(c);
    }
    let mut x = 3;
    let mut m = n;
    while x * x <= m {
        let (c, n) = factor_sub(m, x);
        if c > 0 {
            rec.push(c);
        }
        m = n;
        x += 2;
    }
    if m > 1 {
        rec.push(1);
    }
}

fn help(n: i64) -> i64 {
    if n <= 2 {
        1
    } else if n <= 5 {
        2
    } else if n <= 9 {
        3
    } else if n <= 14 {
        4
    } else if n <= 20 {
        5
    } else if n <= 27 {
        6
    } else if n <= 35 {
        7
    } else if n <= 44 {
        8
    } else {
        9
    }
}


#![allow(unused_imports)]
use proconio::input;
use std::collections::HashMap;
use ascii::*;

fn main() {
    input!(mut n: i64);
    if n == 1 {
        println!("0");
        return;
    }
    let mut factor_list: Vec<(i64, i64)> = Vec::new();
    let initial_n = n;
    let mut n_is_prime = true;
    for i in 2..=(f64::sqrt(n as f64) as i64) {
        let mut count = 0;
        while n % i == 0 {
            n /= i;
            count += 1;
            n_is_prime = false;
        }
        if count > 0 {
            factor_list.push((i, count));
        }
    }
    if n_is_prime {
        factor_list.push((initial_n, 1));
    }
    let mut count = 0;
    for item in factor_list.as_mut_slice() {
        let mut a = 1;
        while item.1 - a >= 0 {
            item.1 -= a;
            count += 1;
            a += 1;
        }
    }
    println!("{}", count);
}


#![allow(unused_imports)]
use proconio::input;
use std::collections::HashMap;
use ascii::*;

fn main() {
    input!(mut n: i64);
    if n == 1 {
        println!("0");
        return;
    }
    let mut factor_list: Vec<(i64, i64)> = Vec::new();
    let initial_n = n;
    let mut n_is_prime = true;
    for i in 2..=(f64::sqrt(n as f64) as i64) {
        let mut count = 0;
        while n % i == 0 {
            n /= i;
            count += 1;
            n_is_prime = false;
        }
        if count > 0 {
            factor_list.push((i, count));
        }
    }
    if n_is_prime {
        factor_list.push((initial_n, 1));
    }
    let mut count = 0;
    for item in factor_list.as_mut_slice() {
        let mut a = 1;
        while item.1 - a >= 0 {
            item.1 -= a;
            count += 1;
            a *= 2;
        }
    }
    println!("{}", count);
}


use proconio::{input, fastout};

fn is_prime(i: f64) -> bool {
    let i_int = i as i64;
    let end = i.sqrt() as i64;
    let mut flag = true;
    for j in 2..end {
        if i_int % j == 0 {
            flag = false;
            break;
        }
    }

    return flag;
}
fn prime_factorization(n: f64) -> i64 {
    let mut _n = n;
    let mut i = 2.0_f64;
    let mut count = 1;
    if _n == 1.0 {
        count = 0;
    }
    while _n.sqrt() > i {
        if _n % i == 0.0 && is_prime(i) {
            _n = _n / i;
            count += 1;
        }
        i += 1.0;
    }
    return count;
}

#[fastout]
fn main() {
    input!{
        n: f64,
    }
    println!("{}", prime_factorization(n));

}


var N = Int(readLine()!)!
var p = 2
var ans = 0
while p * p < N {
    var z = p
    while N % z == 0 {
        ans += 1
        N /= z
        z *= p
    }
    while N % p == 0 {
        N /= p
    }
    p += 1
}
print(N > 1 ? ans + 1 : ans)


import Foundation
let main: () = {
    let N = nextInt()
    let fa = factorize(N)
    var ans = 0
    for (_, P) in fa {
        var p = P
        var b = 1
        while p >= b {
            ans += 1
            p -= b
            b += 1
        }
    }
    print(ans)
}()

func factorize(_ N: Int) -> [(Int, Int)] {
    var r = [(Int, Int)]()
    var n = N
    var i = 2
    while (i * i <= n) {
        if (n % i == 0) {
            var m = 0
            while (n % i == 0) {
                n /= i
                m += 1
            }
            if (m > 0) { r.append((i, m)) }
        }
        i += 1
    }
    if (n != 1) { r.append((n, 1)) }
    return r
}

//----------------------------------

let dx = [1, 0, -1, 0] //[1, 0, -1, 0, -1,  1, -1, 1]
let dy = [0, 1, 0, -1] //[0, 1, 0, -1, -1, -1,  1, 1]

@inlinable func gcd(_ a: Int, _ b: Int) -> Int { (b > 0) ? gcd(b, a % b) : a }
@inlinable func lcm(_ a: Int, _ b: Int) -> Int { a / gcd(a, b) * b }

//----------------------------------

infix operator  =~ : ComparisonPrecedence
infix operator !=~ : ComparisonPrecedence
func =~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { !(right ~= left) }
func =~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { !(right ~= left) }

func =~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { right.contains(left) }
func !=~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { !right.contains(left) }

infix operator /^ : MultiplicationPrecedence
infix operator /^= : AssignmentPrecedence
func /^ <T: FixedWidthInteger>(left: T, right: T) -> T { (left + (right - 1)) / right }
func /^= <T: FixedWidthInteger>(left: inout T, right: T) { left = (left + (right - 1)) / right }

@inlinable func chmax<T: Comparable>(_ m: inout T, _ q: T) { if (m < q) { m = q } }
@inlinable func chmin<T: Comparable>(_ m: inout T, _ q: T) { if (m > q) { m = q } }
@inlinable func chRmax<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m < q) { m = q; return true } else { return false } }
@inlinable func chRmin<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m > q) { m = q; return true } else { return false } }

prefix operator *
prefix func * <T> (a: [T]) -> (T, T) { (a[0], a[1]) }
prefix func * <T> (a: [T]) -> (T, T, T) { (a[0], a[1], a[2]) }
prefix func * <T> (a: [T]) -> (T, T, T, T) { (a[0], a[1], a[2], a[3]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4], a[5]) }

func printErr(_ str: String, terminator: String = "\n") {
    let s = str + terminator
    FileHandle.standardError.write(s.data(using: .utf8)!)
    FileHandle.standardError.synchronizeFile()
}

@inlinable func next() -> String { readLine()! }
@inlinable func nextInt() -> Int { Int(next())! }
@inlinable func nextDouble() -> Double { Double(next())! }
@inlinable func listOfString() -> [String] { next().split(separator: " ").map(String.init) }
@inlinable func listOfInt() -> [Int] { listOfString().map { Int($0)! } }
@inlinable func listOfInt(_ offset: Int = 0) -> [Int] { listOfString().map { Int($0)! + offset } }
@inlinable func listOfInt(_ offsets: Int ...) -> [Int] { listOfString().enumerated().map { Int($0.element)! + offsets[$0.offset % offsets.count] } }
@inlinable func listOfDouble(_ offset: Double = 0.0) -> [Double] { listOfString().map { Double($0)! + offset } }
@inlinable func listOfDouble(_ offsets: Double ...) -> [Double] { listOfString().enumerated().map { Double($0.element)! + offsets[$0.offset % offsets.count] } }

extension Int {
    init(s: String) { self.init(s)! }
    var isEven: Bool { self.isMultiple(of: 2) }
    var isOdd: Bool { !self.isEven }
    var isTrue: Bool { self != 0 }
    var isFalse: Bool { !self.isTrue }
    var toString: String { String(self) }
    var toChar: Character { Character(UnicodeScalar(UInt8(self))) }
}
func + (left: Int, right: Bool) -> Int { left + (right ? 1 : 0) }
extension Character {
    var asciiCode: Int { Int(self.asciiValue!) }
    var string: String { String(self) }
}
extension String {
    @inlinable subscript (position: Int) -> Character { self[self.index(self.startIndex, offsetBy: position)] }
    @inlinable func repeate(_ times: Int) -> String { String(repeating: self, count: times) }
    //  @inlinable subscript (n: Int) -> String { String(self[self.index(self.startIndex, offsetBy: n)]) }
    //  @inlinable subscript (n: Int) -> Int { Int(self[self.index(self.startIndex, offsetBy: n)].asciiValue!) }
    var toInt: Int { Int(self)! }
}
extension String { // VB like
    @inlinable func _index(_ position: Int) -> String.Index! {
        if !(0 ..< self.count ~= position) { return nil }
        return self.index(self.startIndex, offsetBy: position)
    }
    @inlinable func mid(from index: Int, length: Int) -> String! {
        if let startPosition = self._index(index) {
            if let endPosition = self._index(index + length - 1) {
                return String(self[startPosition...endPosition])
            } else {
                let endPosition = self.index(before: self.endIndex)
                return String(self[startPosition...endPosition])
            }
        }
        return ""
    }
    @inlinable func left(_ length: Int) -> String { String(self.prefix(length)) }
    @inlinable func right(_ length: Int) -> String { String(self.suffix(length)) }
}

extension Dictionary {
    @inlinable mutating func getOrSet(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored }
        else {
            let newValue = defaultValue()
            self[key] = newValue
            return newValue
        }
    }
    @inlinable mutating func getOrElse(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored } else { return defaultValue() }
    }
    @inlinable func containsKey(_ key: Key) -> Bool { self.keys.contains(key) }
}

extension Set {
    static func += (left: inout Set<Element>, right: Element) { left.insert(right) }
    static func -= (left: inout Set<Element>, right: Element) { left.remove(right) }
}

extension Array {
    static func += (left: inout Array<Element>, right: Element) { left.append(right) }
    init(_ size: Int, _ initValue: ((Int) -> Element)) {
        self = [Element]()
        for index in 0 ..< size {
            let value = initValue(index)
            self.append(value)
        }
    }
    init(_ size: Int, _ initValue: (() -> Element)) {
        self = [Element]()
        for _ in 0 ..< size {
            let value = initValue()
            self.append(value)
        }
    }
}
typealias IntArray = Array<Int>
typealias DoubleArray = Array<Double>
typealias BoolArray = Array<Bool>
typealias StringArray = Array<String>

extension Array where Element == Int {
    init(_ size: Int) {
        self = [Element](repeating: 0, count: size)
    }
}
extension Array where Element == Double {
    init(_ size: Int) {
        self = [Element](repeating: 0.0, count: size)
    }
}
extension Array where Element == Bool {
    init(_ size: Int) {
        self = [Element](repeating: false, count: size)
    }
}
extension Array where Element == String {
    init(_ size: Int) {
        self = [Element](repeating: "", count: size)
    }
}

extension Array {
    @inlinable func count(_ predicate: ((Element) -> Bool)) -> Int {
        var cnt = 0; for e in self { if (predicate(e)) { cnt += 1 } }
        return cnt
    }
    @inlinable func groupBy<K>(_ keySelector: (Element) -> K) -> [K : [Element]] {
        var destination = [K : [Element]]()
        for element in self {
            let key = keySelector(element)
            var list = destination.getOrSet(key) { [Element]() }
            list.append(element)
            destination[key] = list
        }
        return destination
    }
    @inlinable func groupByIndexed<K>(_ keySelector: (Element) -> K) -> [K : [Int]] {
        var destination = [K : [Int]]()
        for element in self.enumerated() {
            let key = keySelector(element.element)
            var list = destination.getOrSet(key) { [Int]() }
            list.append(element.offset)
            destination[key] = list
        }
        return destination
    }
}

extension Array {
    func binarySearch(_ element: Element, by compare: (Element, Element) -> Int, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            let cmp = compare(midVal, element)
            if (cmp < 0) { low = mid + 1 }          //-1
            else if (0 < cmp) { high = mid - 1 }    // 1
            else { return mid } // key found        // 0
        }
        return -(low + 1)  // key not found
    }
}
extension Array where Element : Comparable {
    func binarySearch(_ element: Element, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            if (midVal < element) { low = mid + 1 }
            else if (midVal > element) { high = mid - 1 }
            else { return mid } // key found
        }
        return -(low + 1)  // key not found
    }
}

extension Array where Element == Int {
    @inlinable func distinct() -> [Element] {
        var set = Set<Element>(), ary = [Element]()
        for n in self.indices { if !set.contains(self[n]) { ary.append(self[n]); set.insert(self[n]) } }
        return ary
    }
    @inlinable func any(_ predicate: (Element) -> Bool) -> Bool {
        var any = false; for element in self { if predicate(element) { any = true } }
        return any
    }
    @inlinable func all(_ predicate: (Element) -> Bool) -> Bool {
        self.allSatisfy(predicate)
    }
    @inlinable func sum() -> Element { self.reduce(0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}

extension Array where Element == Double {
    @inlinable func sum() -> Element { self.reduce(0.0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0.0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}
extension Array where Element == String {
    @inlinable func toIntDouble() -> (Int, Double) { (Int(self[0])!, Double(self[1])!) }
    @inlinable func toIntString() -> (Int, String) { (Int(self[0])!, self[1]) }
    @inlinable func toIntIntString() -> (Int, Int, String) { (Int(self[0])!, Int(self[1])!, self[2]) }
}

@inlinable func block( _ action: () -> Void) {
    action()
}
@inlinable func repeate(_ times1: Int, _ action: () -> Void) {
    for _ in 0 ..< times1 { action() }
}
@inlinable func repeate(_ times1: Int, _ action: (Int) -> Void) {
    for index1 in 0 ..< times1 {
        action(index1)
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ action: (Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            action(index1, index2)
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ action: (Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                action(index1, index2, index3)
            }
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ times4: Int, _ action: (Int, Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                for index4 in 0 ..< times4 {
                    action(index1, index2, index3, index4)
                }
            }
        }
    }
}

func measureTimeSeconds(block: (() -> Void)) -> Double {
    let startTime = Date()
    block()
    let duration = -startTime.timeIntervalSinceNow
    return duration
}


import Foundation
// 第一引数に、素因数分解したい自然数を渡す
func prime_factorization(n:Int)->[[Int]]{
    // n = 1 なら素因数分解できないので空の二次元配列を返す
    if n == 1{
        return []
    }
    // 戻り値のなる二次元配列を初期化
    var arr:[[Int]] = []
    // nの値を変数に格納
    var temp = n
    // 計算するのは√nまでで十分
    for i in 2...Int(sqrt(Double(n)))+1{
        // 割り切れる -> その数を素因数に持つ
        if temp%i==0{
            var cnt=0
            // 素因数の字数を計算
            while temp%i==0{
                // 割り切れるなら次数を一つ増やす
                cnt+=1
                // tempをiで割る
                temp /= i
            }
            // 素因数とその次数をarrに追加
            arr.append([i,cnt])
        }
    }
    // temp ≠ 1ならtempは素因数なのでarrに追加
    if temp != 1{
        arr.append([temp, 1])
    }
    // arrが空なら n = (素数) なのでarrに追加
    if arr==[] {
        arr.append([n, 1])
    }
    // arrを返す
    return arr
}

// 標準入力の受け取り
let n = Int(readLine()!)!

// nを素因数分解
let factorization = prime_factorization(n:n)

// 答えを入れる変数の初期化
var ans = 0

// 各素因数についてループを回す
for i in factorization{

    // 計算に使う変数を初期化
    var num = i[1]
    var cnt = 1

    // もし以前の操作で選んだどの整数とも異なる整数を作れるなら ans += 1
    while num >= cnt{
        ans += 1
        num -= cnt
        cnt += 1
    }
}

// 答えを出力
print(ans)


import Foundation
let main: () = {
    var P = 2
    var S = Set<Int>(arrayLiteral: 1)
    var ans = 0
    var N = nextInt()
    while N != 1 && !N.isPrime {
        let p = P
        while true {
            var z = p
            while N.isMultiple(of: z) {
                S.insert(z)
                N = N / z
                ans += 1
                z *= p
            }
            break
        }
        P = P.nextPrime
    }
    if !S.contains(N) { ans += 1}
    print(ans)
}()

//----------------------------------

let dx = [1, 0, -1, 0] //[1, 0, -1, 0, -1,  1, -1, 1]
let dy = [0, 1, 0, -1] //[0, 1, 0, -1, -1, -1,  1, 1]

@inlinable func gcd(_ a: Int, _ b: Int) -> Int { (b > 0) ? gcd(b, a % b) : a }
@inlinable func lcm(_ a: Int, _ b: Int) -> Int { a / gcd(a, b) * b }

//----------------------------------

infix operator  =~ : ComparisonPrecedence
infix operator !=~ : ComparisonPrecedence
func =~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: Range<T>) -> Bool { !(right ~= left) }
func =~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { right ~= left }
func !=~ <T: FixedWidthInteger>(left: T, right: ClosedRange<T>) -> Bool { !(right ~= left) }

func =~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { right.contains(left) }
func !=~ <T: Collection > (left: T.Element, right: T) -> Bool where T.Element : Equatable { !right.contains(left) }

infix operator /^ : MultiplicationPrecedence
infix operator /^= : AssignmentPrecedence
func /^ <T: FixedWidthInteger>(left: T, right: T) -> T { (left + (right - 1)) / right }
func /^= <T: FixedWidthInteger>(left: inout T, right: T) { left = (left + (right - 1)) / right }

@inlinable func chmax<T: Comparable>(_ m: inout T, _ q: T) { if (m < q) { m = q } }
@inlinable func chmin<T: Comparable>(_ m: inout T, _ q: T) { if (m > q) { m = q } }
@inlinable func chRmax<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m < q) { m = q; return true } else { return false } }
@inlinable func chRmin<T: Comparable>(_ m: inout T, _ q: T) -> Bool { if (m > q) { m = q; return true } else { return false } }

prefix operator *
prefix func * <T> (a: [T]) -> (T, T) { (a[0], a[1]) }
prefix func * <T> (a: [T]) -> (T, T, T) { (a[0], a[1], a[2]) }
prefix func * <T> (a: [T]) -> (T, T, T, T) { (a[0], a[1], a[2], a[3]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4]) }
prefix func * <T> (a: [T]) -> (T, T, T, T, T, T) { (a[0], a[1], a[2], a[3], a[4], a[5]) }

func printErr(_ str: String, terminator: String = "\n") {
    let s = str + terminator
    FileHandle.standardError.write(s.data(using: .utf8)!)
    FileHandle.standardError.synchronizeFile()
}

@inlinable func next() -> String { readLine()! }
@inlinable func nextInt() -> Int { Int(next())! }
@inlinable func nextDouble() -> Double { Double(next())! }
@inlinable func listOfString() -> [String] { next().split(separator: " ").map(String.init) }
@inlinable func listOfInt() -> [Int] { listOfString().map { Int($0)! } }
@inlinable func listOfInt(_ offset: Int = 0) -> [Int] { listOfString().map { Int($0)! + offset } }
@inlinable func listOfInt(_ offsets: Int ...) -> [Int] { listOfString().enumerated().map { Int($0.element)! + offsets[$0.offset % offsets.count] } }
@inlinable func listOfDouble(_ offset: Double = 0.0) -> [Double] { listOfString().map { Double($0)! + offset } }
@inlinable func listOfDouble(_ offsets: Double ...) -> [Double] { listOfString().enumerated().map { Double($0.element)! + offsets[$0.offset % offsets.count] } }

extension Int {
    init(s: String) { self.init(s)! }
    var isEven: Bool { self.isMultiple(of: 2) }
    var isOdd: Bool { !self.isEven }
    var isTrue: Bool { self != 0 }
    var isFalse: Bool { !self.isTrue }
    var toString: String { String(self) }
    var toChar: Character { Character(UnicodeScalar(UInt8(self))) }
}
func + (left: Int, right: Bool) -> Int { left + (right ? 1 : 0) }
extension Character {
    var asciiCode: Int { Int(self.asciiValue!) }
    var string: String { String(self) }
}
extension String {
    @inlinable subscript (position: Int) -> Character { self[self.index(self.startIndex, offsetBy: position)] }
    @inlinable func repeate(_ times: Int) -> String { String(repeating: self, count: times) }
    //  @inlinable subscript (n: Int) -> String { String(self[self.index(self.startIndex, offsetBy: n)]) }
    //  @inlinable subscript (n: Int) -> Int { Int(self[self.index(self.startIndex, offsetBy: n)].asciiValue!) }
    var toInt: Int { Int(self)! }
}
extension String { // VB like
    @inlinable func _index(_ position: Int) -> String.Index! {
        if !(0 ..< self.count ~= position) { return nil }
        return self.index(self.startIndex, offsetBy: position)
    }
    @inlinable func mid(from index: Int, length: Int) -> String! {
        if let startPosition = self._index(index) {
            if let endPosition = self._index(index + length - 1) {
                return String(self[startPosition...endPosition])
            } else {
                let endPosition = self.index(before: self.endIndex)
                return String(self[startPosition...endPosition])
            }
        }
        return ""
    }
    @inlinable func left(_ length: Int) -> String { String(self.prefix(length)) }
    @inlinable func right(_ length: Int) -> String { String(self.suffix(length)) }
}

extension Dictionary {
    @inlinable mutating func getOrSet(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored }
        else {
            let newValue = defaultValue()
            self[key] = newValue
            return newValue
        }
    }
    @inlinable mutating func getOrElse(_ key: Key, _ defaultValue: () -> Value) -> Value {
        if let stored = self[key] { return stored } else { return defaultValue() }
    }
    @inlinable func containsKey(_ key: Key) -> Bool { self.keys.contains(key) }
}

extension Set {
    static func += (left: inout Set<Element>, right: Element) { left.insert(right) }
    static func -= (left: inout Set<Element>, right: Element) { left.remove(right) }
}

extension Array {
    static func += (left: inout Array<Element>, right: Element) { left.append(right) }
    init(_ size: Int, _ initValue: ((Int) -> Element)) {
        self = [Element]()
        for index in 0 ..< size {
            let value = initValue(index)
            self.append(value)
        }
    }
    init(_ size: Int, _ initValue: (() -> Element)) {
        self = [Element]()
        for _ in 0 ..< size {
            let value = initValue()
            self.append(value)
        }
    }
}
typealias IntArray = Array<Int>
typealias DoubleArray = Array<Double>
typealias BoolArray = Array<Bool>
typealias StringArray = Array<String>

extension Array where Element == Int {
    init(_ size: Int) {
        self = [Element](repeating: 0, count: size)
    }
}
extension Array where Element == Double {
    init(_ size: Int) {
        self = [Element](repeating: 0.0, count: size)
    }
}
extension Array where Element == Bool {
    init(_ size: Int) {
        self = [Element](repeating: false, count: size)
    }
}
extension Array where Element == String {
    init(_ size: Int) {
        self = [Element](repeating: "", count: size)
    }
}

extension Array {
    @inlinable func count(_ predicate: ((Element) -> Bool)) -> Int {
        var cnt = 0; for e in self { if (predicate(e)) { cnt += 1 } }
        return cnt
    }
    @inlinable func groupBy<K>(_ keySelector: (Element) -> K) -> [K : [Element]] {
        var destination = [K : [Element]]()
        for element in self {
            let key = keySelector(element)
            var list = destination.getOrSet(key) { [Element]() }
            list.append(element)
            destination[key] = list
        }
        return destination
    }
    @inlinable func groupByIndexed<K>(_ keySelector: (Element) -> K) -> [K : [Int]] {
        var destination = [K : [Int]]()
        for element in self.enumerated() {
            let key = keySelector(element.element)
            var list = destination.getOrSet(key) { [Int]() }
            list.append(element.offset)
            destination[key] = list
        }
        return destination
    }
}

extension Array {
    func binarySearch(_ element: Element, by compare: (Element, Element) -> Int, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            let cmp = compare(midVal, element)
            if (cmp < 0) { low = mid + 1 }          //-1
            else if (0 < cmp) { high = mid - 1 }    // 1
            else { return mid } // key found        // 0
        }
        return -(low + 1)  // key not found
    }
}
extension Array where Element : Comparable {
    func binarySearch(_ element: Element, fromIndex: Int = 0, toIndex: Int = -1) -> Int {
        var low = fromIndex
        var high = (toIndex == -1) ? self.count - 1 : toIndex - 1
        while (low <= high) {
            let mid = (low + high) >> 1 // safe from overflows
            let midVal = self[mid]
            if (midVal < element) { low = mid + 1 }
            else if (midVal > element) { high = mid - 1 }
            else { return mid } // key found
        }
        return -(low + 1)  // key not found
    }
}

extension Array where Element == Int {
    @inlinable func distinct() -> [Element] {
        var set = Set<Element>(), ary = [Element]()
        for n in self.indices { if !set.contains(self[n]) { ary.append(self[n]); set.insert(self[n]) } }
        return ary
    }
    @inlinable func any(_ predicate: (Element) -> Bool) -> Bool {
        var any = false; for element in self { if predicate(element) { any = true } }
        return any
    }
    @inlinable func all(_ predicate: (Element) -> Bool) -> Bool {
        self.allSatisfy(predicate)
    }
    @inlinable func sum() -> Element { self.reduce(0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}

extension Array where Element == Double {
    @inlinable func sum() -> Element { self.reduce(0.0, +) }
    @inlinable func sum(by predicate: (Element) -> Element) -> Element {
        var sum = 0.0; for e in self { sum += predicate(e) }
        return sum
    }
    @inlinable func joinToString(_ sepatator: String = " ") -> String { self.map { String($0) }.joined(separator: sepatator) }
}
extension Array where Element == String {
    @inlinable func toIntDouble() -> (Int, Double) { (Int(self[0])!, Double(self[1])!) }
    @inlinable func toIntString() -> (Int, String) { (Int(self[0])!, self[1]) }
    @inlinable func toIntIntString() -> (Int, Int, String) { (Int(self[0])!, Int(self[1])!, self[2]) }
}

@inlinable func block( _ action: () -> Void) {
    action()
}
@inlinable func repeate(_ times1: Int, _ action: () -> Void) {
    for _ in 0 ..< times1 { action() }
}
@inlinable func repeate(_ times1: Int, _ action: (Int) -> Void) {
    for index1 in 0 ..< times1 {
        action(index1)
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ action: (Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            action(index1, index2)
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ action: (Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                action(index1, index2, index3)
            }
        }
    }
}
@inlinable func repeate(_ times1: Int, _ times2: Int, _ times3: Int, _ times4: Int, _ action: (Int, Int, Int, Int) -> Void) {
    for index1 in 0 ..< times1 {
        for index2 in 0 ..< times2 {
            for index3 in 0 ..< times3 {
                for index4 in 0 ..< times4 {
                    action(index1, index2, index3, index4)
                }
            }
        }
    }
}

func measureTimeSeconds(block: (() -> Void)) -> Double {
    let startTime = Date()
    block()
    let duration = -startTime.timeIntervalSinceNow
    return duration
}

public extension UInt64 {
    /// (x * y) mod m
    /// unlike naive x * y % m, this does not overflow.
    static func mulmod(_ x:UInt64, _ y:UInt64, _ m:UInt64)->UInt64 {
        if (m == 0) { fatalError("modulo by zero") }
        if (m == 1) { return 1 }
        if (m == 2) { return x & 1 }  // just odd or even
        var a = x % m;
        if a == 0 { return 0 }
        var b = y % m;
        if b == 0 { return 0 }
        var r:UInt64 = 0;
        while a > 0 {
            if a & 1 == 1 { r = (r &+ b) % m }
            a >>= 1
            b = (b << 1) % m
        }
        return r
        // return c_mulmod(a, b, m)
    }
}
public extension UInt {
    /// (x * y) mod m without worring about overflow.
    static func mulmod(_ x:UInt, _ y:UInt, _ m:UInt)->UInt {
        let (xy, overflow) = (x * y, false)  //.multiplyWithOverflow(x, y)
        return !overflow ?  xy % m : UInt(UInt64.mulmod(UInt64(x),UInt64(y),UInt64(m)))
    }
    /// (x ** y) mod m
    static func powmod(_ x:UInt, _ y:UInt, _ m:UInt)->UInt {
        if (m == 0) { fatalError("modulo by zero") }
        if (m == 1) { return 1 }
        if (m == 2) { return x & 1 }  // just odd or even
        var r:UInt = 1, t = x, n = y
        while n > 0 {
            if n & 1 == 1 { r = mulmod(r, t, m) }
            t = mulmod(t, t, m)
            n >>= 1
        }
        return r
    }
    /// Greatest Common Divisor
    static func gcd(_ m:UInt, _ n:UInt)->UInt {
        if n == 0 { return m }
        if m < n { return gcd(n, m) }
        let r = m % n
        return r == 0 ? n : gcd(n, r)
    }
    /// b ** x
    static func ipow(_ b:UInt, _ x:UInt)->UInt {
        var r:UInt = 1, t = b, n = x
        while n > 0 {   // &* is neccessary to avoid overflow exception
            if n & 1 == 1 {
                r = r &* t
            }
            n >>= 1; t = t &* t
        }
        return r
    }
    /// Integer Square Root of `n`
    static func isqrt(_ n:UInt)->UInt {
        var xk = UInt(sqrt(Double(n)))
        if xk <= 67108864 { return (xk)}  //sqrt(2^52)
        repeat {
            let xk1 = (xk + n / xk) / 2
            if xk1 >= xk { return xk }
            xk = xk1
        } while true
    }

    /// Integer Cube Root of `n`
    static func icbrt(_ n:UInt)->UInt {
        if n == 0 { return 0 }
        if n == 1 { return 1 }
        if n == 18446744073709551615 { return 2642245 }
        var xk = n
        repeat {
            let xk1 = (2*xk + n/xk/xk) / 3
            if xk1 >= xk { return xk }
            xk = xk1
        } while true
    }
}
public extension Int {
    /// (x * y) mod m without worring about overflow.
    static func mulmod(_ x:Int, _ y:Int, _ m:Int)->Int {
        let (ax, ay, am) = (abs(x),abs(y),abs(m))
        let sxy = 0 < x ? 0 < y ? 1 : -1 : 1
        return sxy * Int(UInt.mulmod(UInt(ax),UInt(ay),UInt(am)))
    }
    /// Greatest Common Divisor
    static func gcd(_ m:Int, _ n:Int)->Int {
        if m < 0 {
            return gcd(-m, n < 0 ? -n : n)
        }
        if n == 0 { return m }
        if m < n { return gcd(n, m) }
        let r = m % n
        return r == 0 ? n : gcd(n, r)
    }
    /// b ** x
    static func ipow(_ b:Int, _ n:Int)->Int {
        return Int(UInt.ipow(UInt(b), UInt(n)))
    }
    /// Integer Square Root of `n`
    static func isqrt(_ n:Int)->Int {
        return Int(UInt.isqrt(UInt(n)))
    }
}
public extension UInt {
    class Prime {
        public init(){}
        public func generate()->AnyIterator<UInt> {
            var currPrime:UInt = 0
            return AnyIterator {
                let nextPrime = currPrime.nextPrime
                if nextPrime > currPrime {
                    currPrime = nextPrime;
                    return currPrime
                }
                return nil
            }
        }
    }
}
public extension UInt.Prime {
    /// primes less than 2048
    static let tinyPrimes:[UInt] = {
        var ps:[UInt] = [2, 3]
        var n:UInt = 5
        while n < 2048 {
            for p in ps {
                if n % p == 0 { break }
                if p * p > n  { ps.append(n); break }
            }
            n += 2
        }
        return ps
    }()
    /// ### [A014233]
    ///
    /// Smallest odd number for which Miller-Rabin primality test
    /// on bases <= n-th prime does not reveal compositeness.
    ///
    /// [A014233]: https://oeis.org/A014233
    static let A014233:[UInt] = [
        2047,                   // p0   = 2
        1373653,                // p1   = 3
        25326001,               // p2   = 5
        3215031751,             // p3   = 7
        2152302898747,          // p4   = 11
        3474749660383,          // p5   = 13
        341550071728321,        // p6   = 17
        341550071728321,        // p7   = 19
        3825123056546413051,    // p8   = 23
        3825123056546413051,    // p9   = 29
        3825123056546413051,    // p10  = 31
        0                       // p11  = 37; 318665857834031151167461  > UInt.max
    ]
    /// [Miller-Rabin] test `n` for `base`
    ///
    /// [Miller-Rabin]: https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
    class func millerRabinTest(_ n:UInt, base:UInt)->Bool {
        if n < 2      { return false }
        if n & 1 == 0 { return n == 2 }
        var d = n - 1
        while d & 1 == 0 { d >>= 1 }
        var t:UInt = d
        var y = UInt.powmod(base, t, n)
        while t != n-1 && y != 1 && y != n-1 {
            y = UInt.mulmod(y, y, n)
            t <<= 1
        }
        return y == n-1 || t & 1 == 1
    }
    class func isPrime(_ n:UInt)->Bool {
        if n < 2      { return false }
        if n & 1 == 0 { return n == 2 }
        if n % 3 == 0 { return n == 3 }
        if n % 5 == 0 { return n == 5 }
        if n % 7 == 0 { return n == 7 }
        for i in 0..<A014233.count {
            // print("millerRabinTest(\(n), base:\(smallPrimes[i]))")
            if millerRabinTest(n, base:tinyPrimes[i]) == false { return false }
            if n < A014233[i] { break }
        }
        return true
    }
    class func nextPrime(_ n:UInt)->UInt {
        if n < 2 { return 2 }
        var u = n
        u += u & 1 == 0 ? 1 : 2
        while !isPrime(u) { u += 2 }
        return u
    }
    class func prevPrime(_ n:UInt)->UInt {
        if n < 2 { return 2 }
        var u = n
        u -= u & 1 == 0 ? 1 : 2
        while !isPrime(u) { u -= 2 }
        return u
    }
    class func within(_ range:Range<UInt>)->[UInt] {
        var result = [UInt]()
        var p = range.startIndex
        if !p.isPrime { p = p.nextPrime }
        while p < range.endIndex {
            result.append(p)
            p = p.nextPrime
        }
        return result
    }
    /// Try to factor `n` by [Pollard's rho] algorithm
    ///
    /// [Pollard's rho]: https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
    ///
    /// - parameter n: the number to factor
    /// - parameter l: the number of iterations
    /// - parameter c: seed
    class func pollardsRho(_ n:UInt, _ l:UInt, _ c:UInt)->UInt {
        //return UInt(c_pbrho(UInt64(n), UInt64(l), Int32(c)))
        var x:UInt = 2, y:UInt = 2, j:UInt = 2
        for i in 1...l {
            x = UInt.mulmod(x, x, n)
            x += c
            let d  = UInt.gcd(x < y ? y - x : x - y, n);
            if (d != 1) {
                return d == n ? 1 : d
            }
            if (i % j == 0) {
                y = x
                j += j
            }
        }
        return 1
    }
    // cf.
    //   http://en.wikipedia.org/wiki/Shanks'_square_forms_factorization
    //   https://github.com/danaj/Math-Prime-Util/blob/master/factor.c
    static let squfofMultipliers:[UInt] = [
        1,      3,      5,      7,      11,
        3*5,    3*7,    3*11,   5*7,    5*11,
        7*11,   3*5*7,  3*5*11, 3*7*11, 5*7*11, 3*5*7*11
    ]
    /// Try to factor `n` by [SQUFOF] = Shanks' Square Forms Factorization
    ///
    /// [SQUFOF]: http://en.wikipedia.org/wiki/Shanks'_square_forms_factorization
    class func squfof(_ n:UInt)->UInt {
        let ks = squfofMultipliers.filter{n < UInt(Int.max) / $0}.reversed()
        // print("ks=\(ks)")
        for k in ks {
            //            if UInt.multiplyWithOverflow(n, k).overflow { continue }
            //let g = UInt(c_squfof(UInt64(n), UInt64(k)))
            let g = squfof_one(n, k)
            // print("squof(\(n),\(k)) == \(g)")
            if g != 1 { return g }
        }
        return 1
    }
    class func squfof_one(_ n:UInt, _ k:UInt)->UInt {
        // print("n=\(n),k=\(k)")
        if n < 2      { return 1 }
        if n & 1 == 0 { return 2 }
        let rn = UInt.isqrt(n)
        if rn * rn == n { return rn }
        // if overflows just give up
        if n > UInt(Int.max) { return 1 }
        let kn = Int(k) &* Int(n)
        let rkn = Int.isqrt(kn)
        var p0 = rkn
        var q0 = 1
        var q1 = kn &- p0*p0
        var b0, b1, p1, q2 : Int
        for i in 0..<Int.isqrt(2 * rkn) {
            // print("Stage 1: p0=\(p0), q0=\(q0), q1=\(q1)")
            b1 = (rkn &+ p0) / q1
            p1 = b1 &* q1 &- p0
            q2 = q0 &+ b1 &* (p0 - p1)
            if i & 1 == 1 {
                let rq = Int.isqrt(q1)
                if rq * rq == q1 {
                    //  square root found; the algorithm cannot fail now.
                    b0 = (rkn &- p0) / rq
                    p0 = b0 &* rq &+ p0
                    q0 = rq
                    q1 = (kn &- p0*p0) / q0
                    while true {
                        // print("Stage 2: p0=\(p0), q0=\(q0), q1=\(q1)")
                        b1 = (rkn &+ p0) / q1
                        p1 = b1 &* q1 &- p0
                        q2 = q0 &+ b1 &* (p0 - p1)
                        if p0 == p1 {
                            return UInt.gcd(n, UInt(p1))
                        }
                        p0 = p1; q0 = q1; q1 = q2;
                    }
                }
            }
            p0 = p1; q0 = q1; q1 = q2
        }
        return 1
    }
    /// factor `u` and return prime facrors of it in array.
    ///
    /// axiom: `UInt.Prime.factor(u).reduce(1,*) == u` for any `u:UInt`
    ///
    /// It should succeed for all `u <= Int.max` but may fail for larger UInts.
    /// In which case `1` is prepended to the result so the axiom still holds.
    class func factor(_ u:UInt)->[UInt] {
        var n = u
        if n < 2 { return [n] }
        if isPrime(n) { return [n] }
        var result = [UInt]()
        for p in tinyPrimes[0..<83] {
            while n % p == 0 { result.append(p); n /= p }
            if n == 1 { return result }
        }
        if isPrime(n) { return result + [n] }
        if n < UInt(tinyPrimes.last! * tinyPrimes.last!) {
            for p in tinyPrimes[83..<tinyPrimes.count] {
                while n % p == 0 { result.append(p); n /= p }
                if n == 1 { return result }
            }
            if n != 1 { result.append(n) }
            return result
        }
        if isPrime(n) { return result + [n] }
        let l = Swift.min(UInt.isqrt(n), 0x1_0000)
        var d = pollardsRho(n, l, 1)
        if d == 1 {
            d = squfof(n)
        }
        result += d != 1 ? factor(d) + factor(n/d) : [1, n]
        result.sort(by: <)
        return result
    }
}
public extension UInt {
    /// true iff `self` is prime
    var isPrime:Bool { return Prime.isPrime(self) }
    /// the next prime number to `self`
    var nextPrime:UInt { return Prime.nextPrime(self) }
    /// the previous prime number from `self`
    var prevPrime:UInt { return Prime.prevPrime(self) }
    /// the prime factors of `self`
    ///
    /// axiom: `i.primeFactors.reduce(1,*) == i` for any `i:Int`
    ///
    /// for negative integers, `-1` is appended to keep axiom.
    var primeFactors:[UInt] { return Prime.factor(self) }
}
public extension Int {
    /// true iff `self` is prime
    var isPrime:Bool {
        return self < 2 ? false : UInt(self).isPrime
    }
    /// the next prime number to `self`
    var nextPrime:Int { return Int(UInt(self).nextPrime) }
    /// the previous prime number from `self`
    var prevPrime:Int { return Int(UInt(self).prevPrime) }
    /// the prime factors of `self`
    ///
    /// axiom: `u.primeFactors.reduce(1,*) == u` for any `u:UInt`
    ///
    /// It may fail for `u > UInt(Int.max)`.
    /// In which case `1` is prepended to the result.
    var primeFactors:[Int] {
        var result = UInt(abs(self)).primeFactors.map{ Int($0) }
        if self < 0 { result += [-1] }
        return result
    }
}
public extension Int {
    class Prime {
        public init(){}
        public func generate()->AnyIterator<Int> {
            var currPrime = 0
            return AnyIterator {
                if currPrime < 9223372036854775783 {
                    currPrime = currPrime.nextPrime
                    return currPrime
                }
                return nil
            }
        }
    }
}
public extension Int.Prime {
    class func within(_ range:Range<Int>)->[Int] {
        let start = UInt(Swift.max(range.startIndex, 0))
        let end   = UInt(range.endIndex)
        return UInt.Prime.within(start..<end).map{ Int($0) }
    }
}


import Foundation

func sieve(_ x: Int) -> [Bool] {
    let sq = Int(sqrt(Double(N)) + 0.1)
    var array = Array(repeating: true, count: x)
    array[0] = false; array[1] = false
    for p in 2..<sq {
        if !array[p] { continue }
        for i in stride(from: p * p, to: x, by: p) {
            array[i] = false
        }
    }
    return array
}
//　因数分解！

var N = Int(readLine()!)!
var i = 0
var r = 0
if N != 1 {
    let s = sieve(N).enumerated().filter(\.1).map(\.0)

    for p in s {
        if N.isMultiple(of: p) {
            while N.isMultiple(of: p) {
                N = N / p
            }
            r += 1
        }
        i += 1
        if N == 1 { break }
    }
    print(r)
} else {
    print(0)
}