AOJ1060 No Story

問題リンク No Story

  • 解法

分からなかったので解説を見ました(解説の「遅い解法」の方法で攻めていました)。
Lを素因数分解して、
L = p0^e0 * p1^e1 ...
とします。すると、a, bはこの指数を決めて得られる整数となります。
また、LCM(a, b)がLとなるには、全ての指数eiについて、aとbの指数の大きい方がLのeiと一致すればいいことになります。aに相当する指数を決めてしまうと、LCM(a, b)=Lを満たすような整数bが何通りあるかは計算で求めることができます。
この方法だと、a > bのパターンもカウントしてしまっているのでダメです。2で割ろうとすると、1度しか計算されないa==bの分まで減らしてしまってアウトです。ですが、a==bでLCM(a, a)=Lを満たすようなものはLCM(L, L)=Lしかあり得ないし、これは必ず1回登場します。なので、答えを+1してから2で割れば正しく答えが求められます。

  • ソース
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

//No Story
public class AOJ1060 {
	
	int[] c;
	int n, res;
	
	void dfs(int k, int r){
		if(k==n){
			res+=r; return;
		}
		for(int i=0;i<c[k];i++)dfs(k+1, r);
		dfs(k+1, r*(c[k]+1));
	}
	
	void run(){
		Scanner sc = new Scanner(System.in);
		int N = 1000000;
		boolean[] p = new boolean[N+1];
		Arrays.fill(p, true);
		p[0]=p[1]=false;
		List<Integer> l = new ArrayList<Integer>();
		for(int i=2;i<=N;i++)if(p[i]){
			l.add(i);
			for(int j=i+i;j<=N;j+=i)p[j]=false;
		}
		for(;;){
			long L = sc.nextLong();
			if(L==0)break;
			c = new int[100];
			n = 0;
			int i = 0;
			while(L!=1&&i<l.size()){
				long x = l.get(i);
				if(L%x==0){
					while(L!=1&&L%x==0){
						c[n]++;
						L/=x;
					}
					n++;
				}
				i++;
			}
			if(i==l.size()){
				c[n] = 1; n++;
			}
			res = 0;
			dfs(0, 1);
			System.out.println(++res>>1);
		}
	}
	
	public static void main(String[] args) {
		new AOJ1060().run();
	}
}