Koder / 박성훈
article thumbnail

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

 

16563번: 어려운 소인수분해

첫째 줄에는 자연수의 개수 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에는 자연수 ki (2 ≤ ki ≤ 5,000,000, 1 ≤ i ≤ N)가 N개 주어진다.

www.acmicpc.net

소인수분해를 빠르게 해주면 되는 문제.

"런타임 전의 전처리" 태그를 붙여줘도 나쁘지 않지 싶다.

소인수분해를 $k_i$를 입력받을때마다 직접 해주면 시간초과를 받기 쉽다.

소인수 분해를 위한 할수 있는 모든 준비를 미리 처리해둬서

최대한 빠르게 소인수분해를 해야 한다.

 

이를 위해서 수 k의 1이 아닌 약수 중 가장 작은 수를

미리 배열에다가 전처리해서 저장해줬다.

 

이렇게 하면 $k_i$를 입력받았을때 전처리한 배열 값을 참조,

그 수로 바로 출력하고 나눠서 최대한 빠르게 처리할 수 있다.

 

전처리를 위해서 에라토스테네스의 체를 응용했다.

어떠한 수 N에 대해서 N의 배수들을 순회하는데,

아직 배열값이 갱신되지 않은 수 M이 있다면

해당 수를 구성하는 1이 아닌 약수 중 가장 작은 수가 N이라는 말과 같으므로

arr[M] 을 N으로 갱신해주면 된다.

만일 M이 소수라면 자기자신으로 갱신해주면 된다.

 

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

int chk[5000001] = {0};

int main(){
	cin.sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	memset(chk, -1, sizeof(chk));
	chk[0] = 0;
	chk[1] = 1;
	for(int i=2; i<=5000000; i++){
		if(chk[i] != -1) continue;
		chk[i] = i;
		for(int j=i+i; j<=5000000; j+=i) if(chk[j] == -1) chk[j] = i;
	}
	
	int T,N;
	cin >> T;
	while(T--){
		cin >> N;
		while(N > 1){
			cout << chk[N] << " ";
			N /= chk[N];
		}
		cout << "\n";
	}
	return 0;
}

N이 1e6이므로 fastio를 사용해주도록 하자.

반응형