알고리즘/알고리즘 공부 내용 정리

백준 BOJ 풀이 : 이분 탐색 문제들 위주 풀이 (220722)

restudy 2022. 7. 22. 13:49
반응형

백준 BOJ 15794번 : Count

문제 난이도 : Silver I

알고리즘 분류 : 두 포인터, 이분 탐색

 

길이 N인 수열이 주어질 때 a_i + a_j와 M의 차이의 절댓값이 가장 작게 하는 a_i + a_j 값을 구하고, 그러한 (a_i, a_j) 쌍이 몇 개나 존재하는지를 구하는 문제이다.

 

경우의 수를 구하는 문제이므로 수열의 순서는 답에 영향을 주지 않는다.

따라서 정렬을 수행한 뒤 두 포인터로 M과 차이가 가장 작은 a_i + a_j의 값을 구해줄 수 있다.

 

이제 경우의 수를 구해주어야 하는데, 이는 이분 탐색을 이용하여 a_i + a_j 값이 앞서 구한 최소 diff 값을 만족하는 경우를 구해주면 된다.

diff 값은 차이의 절댓값을 의미하므로 차이가 +diff인 경우와 -diff인 경우를 모두 고려해주어야 한다.

이 때 diff = 0이면 부호를 고려할 필요가 없으므로 적절히 예외 처리를 해준다.

생각보다 실수할 수 있는 부분이 많은 문제이다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    vector<int> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    int M; cin >> M;

    sort(v.begin(), v.end());

    int l = 0, r = N-1, diff = INT_MAX;

    while(l < r) {
        diff = min(diff, abs(v[l] + v[r] - M));

        if(v[l] + v[r] < M) l++;
        else r--;
    }

    int ans = 0;
    for(int i=0; i<N; i++) {
        ans += upper_bound(v.begin()+i+1, v.end(), -v[i] + M + diff)
               - lower_bound(v.begin()+i+1, v.end(), -v[i] + M + diff);

        if(diff != 0) ans += upper_bound(v.begin()+i+1, v.end(), -v[i] + M - diff)
                             - lower_bound(v.begin()+i+1, v.end(), -v[i] + M - diff);
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 11423번 : Primes

문제 난이도 : Silver II

알고리즘 분류 : 에라토스테네스의 체, 이분 탐색

 

여러 테스트케이스에 대한 a, b 값이 주어질 때 a 이상 b 이하의 소수의 개수를 출력하는 문제이다.

이 때 b는 1,000만 이하이다.

 

최댓값이 1,000만 이하이므로 에라토스테네스의 체를 이용하여 1,000만 이하의 모든 소수를 구해둘 수 있다.

그 다음 모든 소수들에 대해 a ~ b 범위에 드는 소수들의 개수를 구하면 되는데, 이 과정에서 시간 초과가 발생할 수 있으므로 양단 경계값을 이분 탐색으로 찾아주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    vector<bool> prime(10000001, true);
    prime[1] = false;
    for(int i=2; i*i<=10000000; i++)
        for(int j=2; i*j<=10000000; j++) prime[i*j] = false;

    vector<int> v;
    for(int i=2; i<=10000000; i++)
        if(prime[i]) v.push_back(i);

    int a, b;

    while(cin >> a >> b) {
        int l = 0, r = v.size()-1, x = v.size()-1;

        while(l <= r) {
            int m = (l + r)/2;

            if(v[m] >= a) {
                x = min(x, m);
                r = m - 1;
            }
            else l = m + 1;
        }

        l = 0, r = v.size()-1;
        int y = 0;

        while(l <= r) {
            int m = (l + r)/2;

            if(v[m] <= b) {
                y = max(y, m);
                l = m + 1;
            }
            else r = m - 1;
        }

        cout << y - x + 1 << "\n";
        cout << "\n";
    }
}

 

 

백준 BOJ 19554번 : Guess the number

문제 난이도 : Silver III

알고리즘 분류 : 이분 탐색 (+ 인터랙티브)

 

N이 주어지고 1 ~ N 사이의 자연수를 답으로 할 때, up or down으로만 답을 찾아내는 인터랙티브 문제이다.

 

쉽게 말해 이분 탐색을 인터랙티브로 구현하는 문제이다.

left = 1, right = N으로 잡고 mid = (left + right)/2로 하여 mid 값이 답인지를 물어보고, up down에 따라 범위를 조정하는 과정을 반복해주면 된다.

졸려서 그런지 left right 값의 조정을 반대로 설정해놓고 계속 버퍼를 잘못 비워서 틀렸나 하면서 엉뚱한 곳을 고치고 있었다..

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    int l = 1, r = N;

    while(l <= r) {
        int m = (l + r)/2;

        cout << "? " << m << endl;

        int x; cin >> x;

        if(x == 0) {
            cout << "= " << m << endl;
            break;
        }

        if(x < 0) l = m + 1;
        else if(x > 0) r = m - 1;
    }
}

 

 

백준 BOJ 6010번 : Music Notes

문제 난이도 : Silver II

알고리즘 분류 : 누적 합, 이분 탐색

 

N개의 음표가 차례대로 지속되는 시간이 주어지고, M개의 쿼리에 대해 특정 시간 값이 주어질 때 해당 시간에 연주되고 있던 음표의 번호를 구하는 문제이다.

 

시간은 음표의 지속 시간들의 누적 값이므로 음표들의 지속 시간에 대한 누적 합 배열을 구해준다.

그 다음 M개의 쿼리에 대해 시간을 입력받아 이분 탐색으로 해당 시간이 포함되는 최소 번째 구간을 구해준다.

이 때 음표는 0초부터 연주가 되기 시작하므로, 반대로 입력받은 시간을 1초 늘린 뒤 해당 값이 포함되는 최소 번째 구간을 찾아주는 방식을 사용하면 편리하다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(N+1);
    for(int i=1; i<=N; i++) {
        int x; cin >> x;

        v[i] = v[i-1] + x;
    }

    while(M--) {
        int x; cin >> x;

        x++;

        int l = 1, r = N, ans = N;

        while(l <= r) {
            int m = (l + r)/2;

            if(v[m] >= x) {
                ans = min(ans, m);
                r = m - 1;
            }
            else l = m + 1;
        }

        cout << ans << "\n";
    }
}

 

 

백준 BOJ 16401번 : 과자 나눠주기

문제 난이도 : Silver II

알고리즘 분류 : 이분 탐색

 

N명의 사람에게 M개의 과자를 최대 길이로 동일하게 나눠줄 때 그 최댓값을 구하는 문제이다.

 

이분 탐색을 활용하여 과자의 길이를 먼저 가정하고 N명 이상에게 나눠줄 수 있는지를 체크하여 그 최댓값을 구해주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(M);
    for(int i=0; i<M; i++) cin >> v[i];

    int l = 1, r = INT_MAX, ans = 0;

    while(l <= r) {
        int m = (l + r)/2;

        int sum = 0;
        for(int i=0; i<M; i++) sum += v[i] / m;

        if(sum >= N) {
            ans = max(ans, m);
            l = m + 1;
        }
        else r = m - 1;
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 11663번 : 선분 위의 점

문제 난이도 : Silver III

알고리즘 분류 : 정렬, 이분 탐색

 

1차원 좌표 위의 점 N개와 선분 M개의 끝 점이 주어진다고 할 때, 각 선분 위에 있는 점의 수를 구하는 문제이다.

 

먼저 점의 위치를 오름차순으로 정렬해준 뒤에, 각 선분에 대해 양 끝 점 안에 들어오는 점의 범위를 이분 탐색하면 된다.

점들 중 선분 내에 들어오는 가장 왼쪽 점의 번호를 이분 탐색 해주고, 선분 내에 들어오는 가장 오른쪽 점의 번호를 이분 탐색 해주어 개수를 세어줄 수 있다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    sort(v.begin(), v.end());

    while(M--) {
        int a, b; cin >> a >> b;

        int l = 0, r = N-1, x = INT_MAX, y = INT_MIN;

        while(l <= r) {
            int m = (l + r)/2;

            if(v[m] >= a) {
                x = min(x, m);
                r = m - 1;
            }
            else l = m + 1;
        }

        l = 0, r = N-1;

        while(l <= r) {
            int m = (l + r)/2;

            if(v[m] <= b) {
                y = max(y, m);
                l = m + 1;
            }
            else r = m - 1;
        }

        if(x == INT_MAX || y == INT_MIN) cout << 0 << "\n";
        else cout << y - x + 1 << "\n";
    }
}

 

 

백준 BOJ 14170번 : Counting Haybales

문제 난이도 : Silver III

알고리즘 분류 : 정렬, 이분 탐색

 

위의 문제와 완전히 동일한 문제이다.

풀이 코드도 완전히 동일하다.

 

 

백준 BOJ 1072번 : 게임

문제 난이도 : Silver III

알고리즘 분류 : 이분 탐색

 

게임 횟수와 승리 횟수가 주어질 때, 소숫점 아래를 버린 승률이 변하기 위해서는 앞으로 몇 게임을 연승해야 하는지를 구하는 문제이다.

 

게임 횟수가 a, 승리 횟수가 b라면 b * 100 / a로 정수 승률을 구할 수 있다.

이분 탐색을 활용하여 (b + m) * 100 / (a + m) 값이 위의 승률과 다른지를 체크해가면서 최소 정답을 탐색해주면 된다.

이분 탐색 결과값이 오른쪽 끝으로 붙으면 승률이 절대 변하지 않는 것이므로 -1을 출력해주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin >> a >> b;

    int x = b * 100 / a;

    int l = 1, r = INT_MAX, ans = INT_MAX;

    while(l <= r) {
        int m = (l + r)/2;

        int y = (b + m) * 100 / (a + m);

        if(x != y) {
            ans = min(ans, m);
            r = m - 1;
        }
        else l = m + 1;
    }

    if(ans != INT_MAX) cout << ans << "\n";
    else cout << -1 << "\n";
}

 

 

백준 BOJ 10263번 : Opening Ceremony

문제 난이도 : Silver III

알고리즘 분류 : 그리디

 

N개의 높이가 주어진 블럭들 중 하나의 블럭을 제거하거나, 특정 높이 이상인 블럭들의 높이를 1 줄인다고 할 때 모든 블럭을 제거하기 위한 최소 연산 횟수를 구하는 문제이다.

 

먼저 특정 높이는 항상 1로 잡는 것이 최선임을 알 수 있다.

이제 최소 연산이 나올 수 있는 경우를 생각하면, 다음의 3가지가 있다.

 

1. 모든 블럭을 하나씩 제거한다. (이 때 연산 횟수는 N)

2. 모든 블럭을 1층씩 제거한다. (이 때 연산 횟수는 a_max)

3. 내림차순 정렬을 한 뒤 특정 번째 블럭까지는 하나씩 제거하고, 그 뒤 블럭들은 1층씩 제거한다.

 

1, 2, 3을 모두 구해 그 중 최솟값을 답으로 얻어주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    vector<int> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    sort(v.begin(), v.end(), greater<int>());

    int ans = min(N, v[0]);

    for(int i=1; i<N; i++) {
        ans = min(ans, i + v[i]);
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 6236번 : 용돈 관리

문제 난이도 : Silver II

알고리즘 분류 : 이분 탐색

 

N일 간 사용하는 돈이 주어지고, 이들 중 특정 금액만큼을 필요한 날마다 (남은 돈을 넣은 상태로) 뽑아서 사용한다고 할 때, M번 이하로 뽑아서 쓸 수 있는 최소 금액을 구하는 문제이다.

(문제에서는 정확히 M번이라고 하였는데 필요하면 입금과 인출을 추가로 반복할 수 있기 때문에 사실상 M번 이하라고 보면 된다.)

 

문제의 핵심은 돈이 모자랄 경우 남은 금액을 입금한 다음 다시 뽑아서 사용한다는 것이므로, 답이 될 수 있는 금액은 N일 간의 사용 금액 중 최댓값 이상이 되어야 한다.

따라서 left 값을 v_max, right 값은 적당히 크게 잡아서 이분 탐색을 수행해주면 답을 얻을 수 있다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(N);
    int Max = 0;

    for(int i=0; i<N; i++) {
        cin >> v[i];
        Max = max(Max, v[i]);
    }

    int l = Max, r = INT_MAX, ans = INT_MAX;

    while(l <= r) {
        int m = (l + r)/2;

        int cnt = 0, cur = 0;

        for(int i=0; i<N; i++) {
            while(v[i] > cur) {
                cur = m;
                cnt++;
            }

            cur -= v[i];
        }

        if(cnt <= M) {
            ans = min(ans, m);
            r = m - 1;
        }
        else l = m + 1;
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 2792번 : 보석 상자

문제 난이도 : Silver II

알고리즘 분류 : 이분 탐색

 

M 종류의 보석(a_1 ~ a_M)을 같은 사람에게는 같은 종류만 나눠주어 N명에게 나누어줄 때, 보석을 가장 많이 받은 사람의 갯수가 최소가 되도록 할 때 그 최솟값을 구하는 문제이다.

 

이분 탐색을 활용하여 보석을 몇 개씩 나눠줄지를 먼저 정하고, 그 다음 그 때 가장 보석을 많이 받은 사람의 개수를 구하여 최솟값을 갱신해주는 방식으로 풀이하면 된다.

a개의 보석을 b명한테 최대한 균일하게 나누어줄 때 보석을 가장 많이 받은 사람의 보석의 개수는 (a - 1)/b + 1로 간단하게 나타낼 수 있음을 알아두자.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(M);
    for(int i=0; i<M; i++) cin >> v[i];

    int l = 1, r = INT_MAX, ans = INT_MAX;

    while(l <= r) {
        int m = (l + r)/2;

        int sum = 0;
        for(int i=0; i<M; i++) sum += (v[i] - 1)/m + 1;

        if(sum <= N) {
            ans = min(ans, m);
            r = m - 1;
        }
        else l = m + 1;
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 1614번 : 영식이의 손가락

문제 난이도 : Silver III

알고리즘 분류 : 구현

 

손가락을 1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5, 4, 3, 2, ...의 순서로 카운트한다면 a번째 손가락을 b번까지만 사용할 수 있다고 할 때 수를 몇까지 셀 수 있는지 구하는 문제이다.

 

먼저 손가락 번호로 매긴 수열은 주기가 8인 수열임을 알 수 있고, 1번 손가락과 5번 손가락은 1번씩 카운트 되며 나머지 손가락은 2번씩 카운트 됨을 알 수 있다.

따라서 두 경우를 나누어 조건문을 작성해주고, 주기인 8 단위로 나누어 카운트를 해준 뒤 나머지는 직접 카운트 해주는 식으로 구현해주면 된다.

8으로 나눈 나머지 개수만큼을 카운트하는 부분의 구현이 간단하지는 않은데, v[8] = {1, 2, 3, 4, 5, 4, 3, 2}처럼 놓고 반복문을 돌려서 세어주면 조금 수월하다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int a, b; cin >> a >> b;

    int ans = 0;

    if(a == 1 || a == 5) {
        ans += b*8;

        if(a == 5) ans += 4;
    }
    else {
        ans += (b/2) * 8;

        int v[8] = {1, 2, 3, 4, 5, 4, 3, 2};

        for(int i=0; i<8; i++) {
            if(v[i] == a) {
                if(b % 2 == 0) break;
                else b--;
            }

            ans++;
        }
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 17124번 : 두 개의 배열

문제 난이도 : Silver III

알고리즘 분류 : 이분 탐색

 

수열 A와 B에 대해, 새로운 수열 C의 원소 c_i를 a_i와 가장 가까운 B의 원소의 값으로 정의할 때, 수열 C의 원소들의 합을 구하는 문제이다.

 

수열 B의 순서는 답에 영향을 주지 않으므로, 수열 B를 오름차순 정렬한 뒤 이분 탐색으로 각 원소들을 구해주면 된다.

중요한 점은 a_i와 가장 가까운 B의 원소가 2개일 때 작은 것을 사용해야 한다는 것이다.

이 조건을 놓치고 풀어서 어떤 부분이 잘못 되었는지 찾느라 시간을 낭비했다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int T; cin >> T;

    while(T--) {
        int N, M; cin >> N >> M;

        vector<int> v(N), u(M);
        for(int i=0; i<N; i++) cin >> v[i];
        for(int i=0; i<M; i++) cin >> u[i];

        sort(u.begin(), u.end());

        vector<int> w(N);
        for(int i=0; i<N; i++) {
            int l = 0, r = M-1, diff = INT_MAX;

            while(l <= r) {
                int m = (l + r)/2;

                if(abs(v[i] - u[m]) < abs(diff)) {
                    w[i] = u[m];
                    diff = v[i] - u[m];
                }
                else if(abs(v[i] - u[m]) == abs(diff) && u[m] < w[i]) {
                    w[i] = u[m];
                }

                if(v[i] - u[m] == 0) break;

                if(v[i] - u[m] > 0) l = m + 1;
                else if(v[i] - u[m] < 0) r = m - 1;
            }
        }

        int sum = 0;
        for(int i=0; i<N; i++) sum += w[i];

        cout << sum << "\n";
    }
}

 

 

백준 BOJ 9873번 : Cow Baseball

문제 난이도 : Silver III

알고리즘 분류 : 브루트포스

 

N마리의 소들이 1차원 좌표 위에 서 있고, 세 소를 뽑았을 때 3번째 소의 위치 - 2번째 소의 위치가 2번째 소의 위치 - 1번째 소의 위치보다 크거나 같고 2배보다 작거나 같을 때 가능한 조합의 수를 구하는 문제이다.

 

C++은 속도가 빠른 편에 속하고 N = 1000 이하이므로 O(N^3)에도 충분히 돌아간다.

따라서 브루트포스로 구현이 가능하다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    vector<int> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    sort(v.begin(), v.end());

    int ans = 0;
    for(int i=0; i<N; i++)
        for(int j=i+1; j<N; j++)
            for(int k=j+1; k<N; k++)
                if(v[k] - v[j] >= v[j] - v[i]
                   && v[k] - v[j] <= (v[j] - v[i]) * 2) ans++;

    cout << ans << "\n";
}

 

 

백준 BOJ 17266번 : 어두운 굴다리

문제 난이도 : Silver IV

알고리즘 분류 : 이분 탐색

 

길이 N인 길 위에 M개의 가로등이 있고, 각 가로등이 양쪽으로 일정한 거리까지 빛을 비춘다고 할 때, 모든 길을 빛으로 덮기 위한 최소 가로등 불빛의 거리를 구하는 문제이다.

 

조건을 만족하는 최솟값을 구하는 문제이기 때문에 이분 탐색으로 풀이할 수 있다.

최소 거리는 1, 최대 거리는 N으로 놓고 이분 탐색을 수행해주면 답을 찾을 수 있다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(M);
    for(int i=0; i<M; i++) cin >> v[i];

    int l = 1, r = N, ans = N;

    while(l <= r) {
        int m = (l + r)/2;

        bool check = true;
        if(v[0] - m > 0) check = false;
        if(v[M-1] + m < N) check = false;
        for(int i=1; i<M; i++)
            if(v[i-1] + m < v[i] - m) check = false;

        if(check) {
            ans = min(ans, m);
            r = m - 1;
        }
        else l = m + 1;
    }

    cout << ans << "\n";
}

 

 

백준 BOJ 20551번 : Sort 마스터 배지훈의 후계자

문제 난이도 : Silver IV

알고리즘 분류 : 정렬, 이분 탐색

 

정렬한 배열에서 특정 수가 몇 번째에 나오는지를 찾고, 만약 나오지 않는다면 -1을 출력하는 문제이다.

 

sort 함수와 upper_bound, lower_bound를 활용할 줄 알면 쉽게 풀 수 있는 문제이다.

만약 벡터 v에 원소 x가 존재하지 않는 경우 upper_bound(v.begin(), v.end(), x) - lower_bound(v.begin(), v.end(), x) 값이 0이기 때문에 -1을 출력해주면 되고, 그렇지 않은 경우 lower_bound로 최초로 나타나는 주소를 출력해주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    vector<int> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    sort(v.begin(), v.end());

    while(M--) {
        int x; cin >> x;

        if(upper_bound(v.begin(), v.end(), x) - lower_bound(v.begin(), v.end(), x) == 0) cout << -1 << "\n";
        else cout << lower_bound(v.begin(), v.end(), x) - v.begin() << "\n";
    }
}

 

 

백준 BOJ 24331번 : ДВА АЛБУМА

문제 난이도 : Silver IV

알고리즘 분류 : 해시를 사용한 집합과 맵

 

N개의 정수와 M개의 정수가 주어질 때, 두 정수열 모두에 포함된 정수의 개수를 구하고, 그 목록을 오름차순으로 출력하는 문제이다.

 

해시를 사용한 집합과 맵으로 풀이하였다.

먼저 N개의 수열을 입력받을 때 map에 체크를 해두었다가, 다음 M개의 수열을 입력받으며 체크가 되어있는 수열만 따로 벡터에 저장한 뒤 정렬해주고 그 size와 목록을 출력하도록 구현하였다.

참고로 이 문제는 이분 탐색으로도 풀이할 수 있다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N, M; cin >> N >> M;

    map<int, bool> m;

    while(N--) {
        int x; cin >> x;

        m[x] = true;
    }

    vector<int> v;

    while(M--) {
        int x; cin >> x;

        if(m[x]) v.push_back(x);
    }

    sort(v.begin(), v.end());

    cout << v.size() << "\n";

    for(int i=0; i<v.size(); i++) cout << v[i] << " ";
    cout << "\n";
}

 

 

백준 BOJ 11976번 : Promotion Counting

문제 난이도 : Silver V

알고리즘 분류 : 수학

 

대회 전과 후의 브론즈, 실버, 골드, 플래티넘 등급의 사람의 수가 주어질 때 각 등급을 승격한 사람의 수를 구하는 문제이다.

 

간단히 방정식을 세워보면, 플래티넘으로 승급한 사람은 플래티넘 사람의 전후 숫자의 차이로 알 수 있다.

골드로 승급한 사람은 골드를 지나 플래티넘까지 승급한 사람까지 고려해야 하므로 플래티넘 사람의 전후 숫자에 골드 사람의 전후 숫자를 합하여 구할 수 있다.

이런 방식으로 세 등급의 전후 차이로 승급한 사람의 수를 구해줄 수 있다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int v[4][2];
    for(int i=0; i<4; i++)
        for(int j=0; j<2; j++) cin >> v[i][j];

    int a = (v[1][1] - v[1][0]) + (v[2][1] - v[2][0]) + (v[3][1] - v[3][0]);
    int b = (v[2][1] - v[2][0]) + (v[3][1] - v[3][0]);
    int c = (v[3][1] - v[3][0]);

    cout << a << "\n" << b << "\n" << c << "\n";
}

 

 

백준 BOJ 9443번 : Arrangement of Contest

문제 난이도 : Bronze III

알고리즘 분류 : 문자열

 

N개의 문자열이 주어질 때, 맨 앞 문자가 A인 문자열, 맨 앞 문자가 B인 문자열, ... 순으로 놓을 때 최대 몇 개의 문자열을 놓을 수 있는지를 구하는 문제이다.

 

N이 크지 않으므로 모든 알파벳에 대해 N개의 문자열을 모두 검사해보면서 답을 구해주면 된다.

 

 

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

main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL), cout.tie(NULL);

    int N; cin >> N;

    vector<string> v(N);
    for(int i=0; i<N; i++) cin >> v[i];

    int ans = 0;
    for(int i=0; i<26; i++) {
        bool check = false;
        for(int j=0; j<N; j++)
            if(v[j][0] == char('A' + i)) check = true;

        if(check) ans++;
        else break;
    }

    cout << ans << "\n";
}

 

 

 

반응형