소수
소수 판정법
합성수 N에서 1을 제외한 가장 작은 약수는 √N 이하이다.
2부터 √N까지의 수로 나누어지지 않으면 소수이다.
sqrt는 실수값으로 반환되므로 오차가 생길수 있어서 사용하지 않는게 좋기때문에 i의 루프 범위를 i*i <= n으로 잡아주면 된다.
범위 내에서의 소수 판정법 - 에라토스테네스의 체
vector<int> sieve(int n) {
vector<int> primes;
vector<bool> state(n + 1, true);
state[1] = false; // 없어도 됨
for (int i = 2; i <= n; ++i) {
if (!state[i]) continue;
for (int j = 2*i; j <= n; j += i)
state[j] = false;
}
for (int i = 2; i <= n; ++i)
if (state[i]) primes.push_back(i);
return primes;
}
시간복잡도 개선안
vector<int> sieve(int n) {
vector<int> primes;
vector<bool> state(n + 1, true);
state[1] = false; // 없어도 됨
for (int i = 2; i*i <= n; ++i) {
if (!state[i]) continue;
for (int j = i*i; j <= n; j += i)
state[j] = false;
}
for (int i = 2; i <= n; ++i)
if (state[i]) primes.push_back(i);
return primes;
}
시간복잡도는 O(NloglogN) 이다.
짤막한 팁) bool type을 vector로 사용하면 1바이트가 아닌 1비트로 저장되어 공간을 줄일 수 있다.
소인수 분해
- N을 i로 나눌수 있으면 i로 나누어지지 않을 때 까지 i를 소인수 목록에 추가하고 N을 i로 나눈다(i >= 2)
- i로 나누어지지 않으면 i를 증가시킨다.
- N이 1이 될 때까지 1~2를 반복한다.
소인수 목록에 들어간 수는 반드시 소수이다.
위와 같은 방식의 시간복잡도는 O(N) 이지만 시간복잡도를 개선한 소수 판별법처럼 O(√N)으로 줄일 수 있다.
i의 루프 범위를 i <= N이 아닌 i*i <= N로 잡고 N이 1이 아닐 경우 그 수를 소인수 목록에 추가해주면 된다.
int main()
{
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
for (int i = 2; i * i <= n; ++i)
{
while (n % i == 0)
{
cout << i << '\n';
n /= i;
}
}
if (n != 1)
cout << n;
return 0;
}
최대 공약수와 최소 공배수
약수 : 어떤 수를 나누어 떨어지게 하는 수
vector<int> divisor(int n) {
vector<int> div;
for (int i = 1; i * i <= n; ++i) {
if (n % i == 0) div.push_back(i);
}
for (int j = (int)div.size() - 1; j >= 0; --j) {
if (div[j] * div[j] == n) continue;
div.push_back(n / div[j]);
}
return div;
}
시간복잡도는 O(√N) 이다.
최대 공약수(GCD) : 두 자연수의 공통된 약수 중 가장 큰 약수
유클리드 호제법을 이용하면 매우 빠르고 간단하게 구할 수 있다.
두 수 A, B에 대해 A를 B로 나눈 나머지를 r이라고 하면 GCD(A,B) = GCD(B,r)이다.
int gcd(int a, int b) {
if (a == 0) return b;
return gcd(b, a%b);
}
최소 공배수(LCM)
A×B = GCD(A,B)×LCM(A,B)
int lcm(int a, int b) {
return a / gcd(a, b) * b;
}
본래의 식은 (a*b) / gcd(a,b) 이지만 a,b의 값이 10^9라면 a*b는 int overflow가 발생하기 때문에 예방차원에서 계산의 순서를 바꾼 것이다.
연립합동방정식
이항계수
nCk = (n-1)C(k-1) + (n-1)Ck
'알고리즘 > 바킹독의 실전 알고리즘' 카테고리의 다른 글
[0x14] 투 포인터 (0) | 2022.08.05 |
---|---|
[0x13] 이분탐색 (0) | 2022.08.05 |
[0x11] 그리디 (0) | 2022.08.04 |
[0x10] 다이나믹 프로그래밍 (0) | 2022.08.03 |
[0x0F] 정렬 II (0) | 2022.08.02 |