読者です 読者をやめる 読者になる 読者になる

階乗の素因数分解の仕方

ABC第52回のFactors of Factorialという問題を解いていたのですが、階乗の素因数分解をする必要がありました。やり方をしらなかったので、その方法のメモです。

この問題の答えを最初intで保持していたためinputが1000のときに正しい答えを得られず1時間ほど悩みました。10*9+7が出てきたときは必ずlongを使うと決めてるといいかもしれません。

import java.util.*;

/* 階乗の素因数分解の仕方。参考: https://youtu.be/28IanD3lXGg */

public class Playground2 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        
        int n = in.nextInt();
    
        int[] numExp = new int[n + 1];
        for (int i = 2; i <= n; i++) {
            int a = i;
            while (a > 1) {
                for (int j = 2; j <= i; j++) {
                    if (a % j == 0) {
                        numExp[j]++;
                        a /= j;
                        break;
                    }
                }
            }
        }
        
        for (int i = 2; i <= n; i++) {
            if (numExp[i] != 0) {
                System.out.printf("%d: %d\n", i, numExp[i]);
            }
        }
    }
    
}

何かの参考になるかもしれないので、一応自分が最初に書いたコードを置いときます。

import java.util.*;

/* 階乗の素因数分解の仕方。参考: https://youtu.be/28IanD3lXGg */

public class Playground2 {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        
        int n = in.nextInt();
        ArrayList<Integer> primes = new ArrayList<Integer>();
        fillPrimes(primes, n);
        printPrimeFactor(primes, n);
    }
    
    // Print prime factor of n factorial
    public static void printPrimeFactor(ArrayList<Integer> primes, int n) {
        for (int i = 0; i < primes.size(); i++) {
            int p = primes.get(i);
            int nn = p;
            int numExp = 0;
            while (nn <= n) {
                numExp += n / nn;
                nn *= p;
            }
            System.out.printf("%d: %d\n", p, numExp);
        }
    }
    
    // Put prime number up to n (inclusive)
    public static void fillPrimes(ArrayList<Integer> primes, int n) {
        int[] prime = new int[n + 1];
        Arrays.fill(prime, 1);
        
        primes.add(2);
        
        for (int i = 3; i <= n; i += 2) {
            if (prime[i] == 1) {
                if (isPrime(i)) {
                    primes.add(i);
                    for (int j = i * 2; j <= n; j += i) {
                        prime[j] = 0;
                    }
                }
            }
        }
    }
    
    public static boolean isPrime(int n) {
        for (int i = 2; i <= Math.sqrt(n); i++) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }
}