※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 1750번 문제인 서로소의 개수이다.
문제는 아래 링크를 확인하자.

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

 

1750번: 서로소의 개수

예제 1의 경우 가능한 경우의 수는 (2, 3), (4, 3), (2, 4, 3)이다.

www.acmicpc.net

주어진 길이 N의 수열의 원소를 선택하는 경우의 수는 각 원소를 선택하거나 안하거나의 관점에서 보았을 때 2N1과 같음을 관찰하자. -1은 아무 원소도 고르지 않는 경우를 제외한 것이다.

 

선택한 원소가 서로소이게 원소를 고르는 경우의 수는 전체 경우의 수에서 선택한 원소가 서로소가 아니게 원소를 고르는 경우의 수를 빼는 것으로 구할 수 있다. 그 경우의 수는 10만 이하의 양의 정수 k에 대하여 주어진 원소들이 모두 k의 배수가 되도록 원소를 고르는 경우의 수를 구할 수 있다면 포제원리(inclusion and exclusion principle)와 뫼비우스 함수(möbius function)를 이용해 빠르게 계산해낼 수 있다. 전체 원소의 개수가 50, 즉 충분히 적은 수이므로 위에서 필요한 값은 주어진 원소 중 k의 배수의 개수를 직접 세는 것으로 충분히 빠르게 구할 수 있다.

 

아래는 제출한 소스코드이다.

#include <iostream>
using namespace std;
typedef long long ll;

char mobius[100001];
bool sieve[100001];

int N;
int arr[50];
ll ans;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	for (int i = 1; i < 100001; i++) mobius[i] = 1;
	for (int i = 2; i < 100001; i++) {
		if (sieve[i]) continue;
		for (int j = i; j < 100001; j += i) {
			mobius[j] *= -1;
			sieve[j] = 1;
		}
		ll sq = (ll)i * i;
		for (ll j = sq; j < 100001; j += sq) mobius[j] = 0;
	}

	cin >> N;
	for (int i = 0; i < N; i++) cin >> arr[i];
	ans = (1LL << N) - 1;
	for (int i = 2; i < 100001; i++) {
		int cnt = 0;
		for (int j = 0; j < N; j++) {
			if (arr[j] % i) continue;
			cnt++;
		}

		ans += ((1LL << cnt) - 1) * mobius[i];
	}

	cout << ans % 10000003;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 2737 // C++] 연속 합  (1) 2024.01.05
[BOJ 7117 // C++] Sevens, twos and zeros  (0) 2024.01.04
[BOJ 2436 // C++] 공약수  (1) 2024.01.02
[BOJ 4108 // C++] 지뢰찾기  (1) 2024.01.01
[BOJ 2624 // C++] 동전 바꿔주기  (1) 2023.12.31

+ Recent posts