Doby's Lab

[알고리즘] 백준 1789번: 수들의 합 (C++) 본문

PS/BOJ

[알고리즘] 백준 1789번: 수들의 합 (C++)

도비(Doby) 2022. 3. 6. 22:27

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

 

1789번: 수들의 합

첫째 줄에 자연수 S(1 ≤ S ≤ 4,294,967,295)가 주어진다.

www.acmicpc.net

처음에 고안했던 방법은 수를 선택 여부에 따라 백트래킹하여 s가 되게끔 만족하는 수의 개수 중 최댓값을 도출하려 했다.

>> 하지만, 이는 엄청난 경우의 수에 따른 메모리 초과뿐만 아니라 결괏값도 도출하지 못했다.

#include <iostream>
using namespace std;

int maxValue = 0;
unsigned int s;

void solve(unsigned int num, int cnt, int plus){
    if(num == s){
        maxValue = max(maxValue, cnt);
        return;
    }
    
    solve(num + plus, cnt + 1, plus + 1);
    solve(num, cnt, plus + 1);
}

int main(){
    cin >> s;
    
    solve(0, 0, 1);
    //cout << "func end";
    cout << maxValue;
    return 0;
}

솔루션

이 문제를 수학적으로 접근한다면 쉽게 풀 수 있었다.

 

서로 다른 N개의 자연수, N의 최댓값이다. 

S를 1부터 작은 수부터 계속 넣다 보면 최댓값을 만들 수 있지 않은가?

예를 들어 200을 1부터 계속 채워 넣으면

{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}

1~20까지 다 더하면 210으로 200을 넘는다.

1~19까지 다 더하면 190인데

1~18까지 더하고, 19를 29로 바꾼다면 200이 되지 않는가?

다음 수들을 다 더하는 것 >> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 29}

 

이와 같은 방법으로 답을 도출하면 되는 문제였다.

허나, 범위가 넓기 때문에 이분 탐색을 사용한다.

정렬과도 상관없으므로 이분 탐색을 사용할 수 있는 조건도 된다.


궁금한 점

이분 탐색을 사용해도 시간 초과가 나서 long long으로 잡아두었던 타입들을 long으로 교체해주니 시간 초과가 일어나지 않고, 통과하였다. 타입이 시간에 무슨 영향을 끼치는 건가?

 

[AC 코드]

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

ll s;

int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    cin >> s;
    
    ll low = 1;
    ll high = s;
    
    ll result;
    while(low <= high){
        ll mid = (low + high) >> 1;
        
        ll sum = (mid + 1) * mid / 2;
        
        if(sum <= s){
            low = mid + 1;
            result = mid;
        }
        else{
            high = mid - 1;
        }
    }
    
    cout << result;
    return 0;
}
728x90