Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기

카테고리 없음

백준 3752번: 최대공약수 행렬식

https://www.acmicpc.net/problem/3752

 

3752번: 최대공약수 행렬식

집합 S = {x1, x2, ..., xn}가 인수에 대해서 닫혀있으려면, 모든 xi ∈ S에 대해서, xi의 모든 약수 d는 d ∈ S를 만족해야 한다. 인수에 대해 닫힌 집합 S를 최대공약수 행렬 (S) = (sij), sij = GCD(xi,xj)로 만

www.acmicpc.net


수학적으로는 어렵지만 코딩은 쉬운 문제입니다.

 

Zhongshan Li의 1990년 paper 을 보면, 3752번에서 쓰는 모든 표현이 그대로 나오고 있습니다. 즉

det[S]=xSϕ(x)

이것을 그대로 구현하면 정답을 받습니다.

 

Totient Function의 구현에 대하여, 문제에서 x<2×109이므로 소인수분해 기반 O(x) 구현이 충분히 통과하고, 다만 범위가 충분히 작기 때문에 constant factor에 의하여 Pollard-Rho 기반 구현은 상대적으로 느릴 수 있습니다. Totient function의 정의 중 하나를 쓰면

ϕ(x)=x×p|x(11p)

주어진 범위에 의해 Eratosthenes' Sieve로 prime factors를 빠르게 얻을 수 있고 totient function도 빠르게 구해집니다.

 

저는 O(x) 구현을 썼습니다.

#include <stdio.h>
#define mod 1000000007

long long PHI (long long x);

int main() {
	
	int T;
	scanf("%d", &T);
	while(T--) {
		int n;
		scanf("%d", &n);
		
		long long answer = 1;
		while(n--) {
			long long temp;
			scanf("%lld", &temp);
			answer = answer * PHI(temp) % mod;
		}
		printf("%lld\n", answer);
	}
	return 0;
}

long long PHI (long long x) {
	long long result = x;
	if (x % 2 == 0) {
		while (x % 2 == 0) {
			x /= 2;
		}
		result -= result / 2;
	}
	for (long long i = 3; i * i <= x; i += 2) {
		if (x % i == 0) {
			while (x % i == 0) {
				x /= i;
			}
			result -= result / i;
		}
	}
	if (x > 1) {
		result -= result / x;
	}
	return result;
}​

(C11, 48ms, 1116KB, 제출번호 55721319)


Sieve를 쓰는 경우 대략 12ms까지 줄일 수 있었습니다. (제출번호 55723997) 2×109<50000 임을 이용하면 sieve를 통해 그 이하의 prime만 구해도 충분함을 알 수 있습니다.