Baekjoon

Baekjoon 17425번 약수의 합

ppwag 2022. 7. 6. 01:46

문제

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

걸린 시간

-

풀이

C++

#include <bits/stdc++.h>
#define INF 1e9
#define all(c) c.begin(), c.end()
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

string ans = "";
const int N = 1e6;
vector<int> nums(N+1);

map<int, int> factor(int n){
    map<int, int> ret;
    while(n > 1){
        ret[nums[n]]++;
        n = n/nums[n];
    }
    return ret;
}

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

    for(int i = 0; i <= N; i++){
        nums[i] = i;
    }
    nums[0] = nums[1] = 0;
    for(int i = 2; i <= N; i++){
        if(nums[i] == i){
            for(int j = i+i; j <= N; j += i){
                if(nums[j] == j){
                    nums[j] = i;
                }
            }
        }
    }

    vector<ull> ps(N+1, 0);
    for(int i = 1; i <= N; i++){
        auto arr = factor(i);
        ull sum = 1;
        for(auto iter = arr.begin(); iter != arr.end(); iter++){
            ull tmp = 0;
            for(int j = 0; j <= iter->second; j++){
                tmp += round(pow(iter->first, j));
            }
            sum *= tmp;
        }
        ps[i] = sum;
    }

    for(int i = 1; i <= N; i++){
        ps[i] += ps[i-1];
    }

    int tc;
    cin >> tc;
    while(tc--){
        int n;
        cin >> n;
        ans += to_string(ps[n]) + '\n';
    }
    cout << ans;
    return 0;
}

자연수 n 의 최대값이 1e6, 테스트케이스 t 가 최대 1e5 개 주어지므로 매번 g(n) 값을 구하면 O(nt) 는 1e11 로 시간안에 해결할 수 없다.

그래서 모든 수의 f(n) 값을 구해두고 누적합으로 g(n) 값을 구한 뒤 주어지는 n 에 O(1) 로 응답하는 방법을 사용했다.

f(n) 을 얼마나 빨리 구하느냐가 문제인데 O(sqrt(n)) 시간안에 모든 약수를 구하는 방법은 총 O(n^1.5), 1e9 * α 로 통과하지 못한다.

더 빠른 시간안에 약수의 합을 구하는 방법을 찾아보니 O(lgN) 으로 소인수분해를 하고, 소인수를 이용하여 약수의 합을 구하는 방법이 존재했다. O(NlgN) 정도면 확실히 통과할 거라 생각하고 js 로 구현하여 제출했는데 시간초과가 났다. 분명 node.js 의 느린 속도 때문이라고 생각해 c++ 로 재작성해서 제출하니 통과했다. (c++ 이 역시 빠르긴 하다.)

node.js 로 통과한 풀이들은 대부분 dp 풀이이고, 가끔 효율적으로 약수를 직접 구한 풀이가 보인다.

dp 풀이, 에라토스테네스의 체를 이용한 빠른 소인수 분해 방법, 오일러의 체, 또 다른 효율적인 약수 개수 구하는 알고리즘 도 공부하면 좋겠지만 알고리즘 대회가 목적이 아니므로... 여기서 접고 구현 문제나 풀어야겠다.

참고

'Baekjoon' 카테고리의 다른 글

Baekjoon 1783번 병든 나이트  (0) 2022.08.27
Baekjoon 1997번 박스포장  (0) 2022.06.02
Baekjoon 18428번 감시 피하기  (0) 2022.05.31
Baekjoon 11057번 오르막 수  (0) 2022.05.27
Baekjoon 1495번 기타리스트  (0) 2022.05.17

댓글