Problem:
Score : 400 points

Problem Statement

Given are positive integers A and B.

Let us choose some number of positive common divisors of A and B.

Here, any two of the chosen divisors must be coprime.

At most, how many divisors can we choose?

Definition of common divisor

An integer d is said to be a common divisor of integers x and y when d divides both x and y.

Definition of being coprime

Integers x and y are said to be coprime when x and y have no positive common divisors other than 1.

Definition of dividing

An integer x is said to divide another integer y when there exists an integer \alpha such that y = \alpha x.

Constraints

All values in input are integers.

1 \leq A, B \leq 10^{12}

Input

Input is given from Standard Input in the following format:

A B

Output

Print the maximum number of divisors that can be chosen to satisfy the condition.

Sample Input 1

12 18

Sample Output 1

3

12 and 18 have the following positive common divisors: 1, 2, 3, and 6.

1 and 2 are coprime, 2 and 3 are coprime, and 3 and 1 are coprime, so we can choose 1, 2, and 3, which achieve the maximum result.

Sample Input 2

420 660

Sample Output 2

4

Sample Input 3

1 2019

Sample Output 3

1

1 and 2019 have no positive common divisors other than 1.

Solution in JavaScript (node.js v5.12) (judge verdict: Accepted)

'use strict'

class Main {
  solve() {
    const arr = input.nextIntArr();
    const a = arr[0];
    const b = arr[1];
    if (a == 1 && b == 1) { return 1; }
    const prime = new Prime();
    const f1 = prime.getFactor(a);
    const f2 = prime.getFactor(b);
    const arr1 = _.sort(_.uniq(f1));
    const arr2 = _.sort(_.uniq(f2));
    let i = 0,j = 0;
    let counter = 0;
    while (i < arr1.length && j < arr2.length) {
      if (arr1[i] == arr2[j]) { ++counter; ++i; ++j; }
      else if (arr1[i] < arr2[j]) { ++i; }
      else { ++j; }
    }
    return counter + 1;
  }
}

class Prime {
  /* 初期化と素数テーブル生成 */
  constructor(n) {
    if (n == null) { n = 1e6; }
    const primeTable = [...((new Array(n)).keys())];
    primeTable[0] = false;
    primeTable[1] = false;
    let max = Math.sqrt(n);
    for(let i = 2;i <= max;++i) {
      if (primeTable[i] !== i) continue;
      for (let j = i * i; j < n; j += i) {
        if (primeTable[j] !== j) continue;
        primeTable[j] = i;
      }
    }
    this.size = n;
    this.primeTable = primeTable;
    this.primeList = primeTable.filter((e,i) => e === i);
  }

  /* テーブルに生成した素数の2乗までの素数判定 */
  isPrime(n) {
    if (n < this.size) return this.primeTable[n] === n;
    let max = Math.sqrt(n);
    for (let i = 0; this.primeList[i] <= max; ++i) {
      if (n % this.primeList[i] === 0) return false;
    }
    return true;
  }

  /* 最小の素因数 */
  getMinimumFactor(n) {
    if (n < this.size) return this.primeTable[n];
    let max = Math.sqrt(n);
    for (let i = 0; this.primeList[i] <= max; ++i) {
      if (n % this.primeList[i] === 0) return this.primeList[i];
    }
    return n;
  }

  /* 素因数の取得
   * 上限: テーブルサイズの二乗*/
  getFactor(n) {
    const ret = [];
    let k = n;
    while(!this.isPrime(k)) {
      const p = this.getMinimumFactor(k)
      ret.push(p);
      k /= p;
    }
    ret.push(k);
    return ret;
  }

  /* 上限: テーブルサイズ*/
  getFactorTable(n) {
    const factor = this.getFactor(n);
    const maxFactor = factor[factor.length - 1];
    const ret = [];
    for (let i = 0;this.primeList[i] <= maxFactor; ++i) {
      ret[this.primeList[i]] = 0;
    }
    for (const e of factor) { ++ret[e]; }
    return ret;
  }

  /* 約数の個数 */
  getDivisorCount(n) {
    const factor = this.getFactor(n);
    let count = 1;
    let prev = factor[0];
    let factorCount = [];
    for (let i = 1; i < factor.length; ++i) {
      if (factor[i] != prev) {
        factorCount.push(count);
        count = 1;
      }
      else {
        ++count;
      }
      prev = factor[i];
    }
    factorCount.push(count);
    return factorCount.reduce((a,b)=>a * (b+1),1);
  }

  /* 約数の一覧の取得(未ソート) O(√n)*/
  static getDivisors(n) {
    let max = Math.sqrt(n);
    let ret = [];
    if (n % max === 0) {ret.push(max);}
    for(let i = 0; i < max; ++i) {
      if (n % i == 0) {
        ret.push(i);
        ret.push(n / i);
      }
    }
    return ret;
  }
}

class Underscore {
   sum(arr) { return arr.reduce((a,b)=>a+b); }
   modSum(arr,mod) { if (mod == null) { mod = MOD.mod; } return arr.reduce((a,b)=>(a+b)%mod); }
   min(arr, func) { if (func == null) {func = (a,b) => a - b} return arr.reduce((a,b) => func(a,b) < 0 ? a : b); }
   max(arr, func) { if (func == null) {func = (a,b) => a - b} return arr.reduce((a,b) => func(a,b) > 0 ? a : b); }
   sort(arr, func) { if (func == null) {func = (a,b) => a - b} return arr.sort(func) }
   uniq(arr) { 
     arr.sort();
     for(let i = 0; i < arr.length - 1; ++i) { 
       arr[i] = arr[i+1] == arr[i] ? null : arr[i]; 
     }
     return arr.filter(e => e != null);
   }
   range(start, stop, step) {
     if (stop == null) {
       stop = start || 0;
       start = 0;
     }
     if (!step) {
       step = stop < start ? -1 : 1;
     }
     const length = Math.max(Math.ceil((stop - start) / step), 0);
     const range = Array(length);
 
     for (var idx = 0; idx < length; idx++, start += step) {
       range[idx] = start;
     }
     return range;
   }
   first (array, n) {
     if (array == null || array.length < 1) return n == null ? void 0 : [];
     if (n == null) return array[0];
     return this.initial(array, array.length - n);
   };
   initial (array, n) { return array.slice.call(array, 0, Math.max(0, array.length - (n == null ? 1 : n))); }
   tail(array, n) { return array.slice.call(array, n == null ? 1 : n); }
   last (array, n) { 
     if (n == null) return array[array.length - 1];
     return this.tail(array, Math.max(0, array.length - n)); 
   }
   /* 累積和 */
   sumArray (arr) { return this.tail(arr.reduce(((a,b,i) => {a.push(b + a[i]); return a}), [0])); }
   diffArray (arr) { const s = []; for (let i = 1; i < arr.length; ++i) { s.push(arr[i] - arr[i-1]); } return s; }
   /* 二分探索による配列検索 */
   binarySearch (array, key, iteratee) {
     const itr = (obj) => (typeof obj === 'object') ? obj[iteratee] : obj;
     const value = itr(obj);
     let low = 0, high = array.length;
     while (low < high) {
       let mid = Math.floor((low + high) / 2);
       if (itr(array[mid]) < value) low = mid + 1; else high = mid;
     }
     return low;
   };
 
 }
 const _ = new Underscore();
class Input {
  constructor() {
    this.cursor = 0;
    this.inputAll();
  }

  inputAll() {
    this.data = (require("fs").readFileSync("/dev/stdin", "utf8")).split('\n');
    return this.data;
  }
  /* 1行 or 複数行文字列 */
  nextLine(n) {
    if (n) {
      const ret = this.data.slice(this.cursor, this.cursor + n);
      this.cursor += n;
      return ret;
    }
    return this.data[this.cursor++];
  }
  /* 1整数 */
  nextInt() { return parseInt(this.nextLine()); } 
  /* 一行文字配列 */
  nextStrArr() { return this.nextLine().split(' '); } 
  /* 一行整数配列 */
  nextIntArr() { return this.nextStrArr().map((e) => parseInt(e)); }
  /* 一行浮動小数点配列 */
  nextFloatArr() { return this.nextStrArr().map((e) => parseFloat(e)); }
  /* 複数行整数配列 */
  nextIntLine(n) { return this.nextLine(n).map((e) => parseInt(e)) }
  /* 複数行浮動小数点配列 */
  nextFloatLine(n) { return this.nextLine(n).map((e) => parseFloat(e)) }
  /* 複数行文字列二次元配列 */
  nextStrRange(n) { return this.nextLine(n).map((line) => line.split(' ')); }
  /* 複数行整数二次元配列 */
  nextIntRange(n) {
    return this.nextLine(n).map((line) => line.split(' ').map((e) => parseInt(e)));
  }
  /* 複数行浮動小数点数二次元配列 */
  nextFloatRange(n) {
    return this.nextLine(n).map((line) => line.split(' ').map((e) => parseFloat(e)));
  }
} 

class Out {
  constructor() {
    this.option = {
      'true': 'Yes',
      'false': 'No',
    };
  }
  write(output){
    let ret;
    if (output == null) return;
    if (output === true) { ret = this.option['true']; }
    else if (output === false) { ret = this.option['false']; }
    else { ret = output; }
    console.log(ret);
  }
  bool(option) {
    this.option['false'] = option[0];
    this.option['true'] = option[1];
    return this;
  }
}
const out = new Out();
const input = new Input();
out.write(new Main().solve());