백준: Gold5 - 2436, 2493, 2589

4 분 소요


계속

2436: 공약수

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

어떤 두 수의 최대공약수와 최소공배수를 입력 받았을 때, 그 두 수의 합이 최소가 되는 두 수 구하기

#include <bits/stdc++.h>

using namespace std;

vector<int> v;
int ansa, ansb;
int a, b;

void func(int ind, int before, int cnt){
    if( cnt == 0 ){
        if( a*before + b/before < ansa + ansb ){
            ansa = a*before;
            ansb = b/before;
        }
        return;
    }
    for(int i = ind+1; i < v.size(); i++){
        func(i, before*v[i], cnt-1);
    }
}

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

    cin >> a >> b;

    int c = b/a;
    for(int i = 2; i <= c; i++){
        if( c % i == 0 ){
            int k = 1;
            while( c % i == 0 ){
                k *= i;
                c /= i;
            }
            v.push_back(k);
        }
    }

    ansa = a; ansb = b;
    for(int i = 0; i <= v.size()/2; i++){
        func(-1, 1, i);
    }

    cout << min(ansa, ansb) << ' ' << max(ansa, ansb) << endl;

}

최대공약수를 a, 최소공배수를 b라고 하면 찾아야 하는 두 수들은 b/a의 약수들을 나눠 가진다는 것을 알 수 있다. 예제인 6, 180을 보면

b/a = 180/6 = 30 = 2 * 3 * 5

a가 최대공약수, b가 최소공배수인 두 수들은
(a, a*2*3*5), (a*2, a*3*5), (a*3, a*2*5), (a*5, a*2*3)

두 수끼리 공약수가 또 있으면 안 되므로,
예를 들어 b/a = 2^n * 3^m * ...인 경우 2^n과 3^m 등으로 통째로 나눠야 함


2493: 탑

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

각 탑들이 왼쪽으로 빛을 쏠 때 가장 먼저 만나는 탑의 인덱스 구하기

방법 1.

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

int arr[500001];
int ans[500001];

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

    int n;
    cin >> n;

    for(int i = 1; i <= n; i++){
        cin >> arr[i];
    }

    priority_queue<P, vector<P>, greater<P>> pq;
    for(int i = n; i > 0; i--){
        while( pq.size() && pq.top().first <= arr[i] ){
            ans[pq.top().second] = i;
            pq.pop();
        }
        pq.push(make_pair(arr[i], i));
    }

    for(int i = 1; i <= n; i++){
        cout << ans[i] << ' ';
    }

}

일단 떠오른 대로 무지성 풀이는 뒤에서부터, (탑 높이, 인덱스)를 우선순위 큐에 넣고, 자기보다 같거나 큰 탑이 나올 때마다 팝하면서 인덱스를 저장해주면 될 것 같다
N은 최대 50만인데, 우선순위 큐는 시간 복잡도가 O(logN)이고, 포문 한 번 도니까 총 O(NlogN)일 듯

방법 2.

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

int arr[500001];
int ans[500001];

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

    int n;
    cin >> n;

    for(int i = 1; i <= n; i++){
        cin >> arr[i];
    }

    stack<P> st;
    for(int i = 1; i <= n; i++){
        while( st.size() && st.top().first < arr[i] ){
            st.pop();
        }
        ans[i] = st.size() ? st.top().second : 0;
        st.push(make_pair(arr[i], i));
    }

    for(int i = 1; i <= n; i++){
        cout << ans[i] << ' ';
    }

}

하지만 보통 이런 문제는 스택으로 풀겠지 싶어서 다시 생각해 봄
이번엔 앞에서부터, 얘가 나랑 만나는 지를 확인하면 된다
만약 스택의 탑이 나보다 작으면 안 만나는 애고, 나보다 뒤의 탑들도 얘를 만날 일이 없으니 팝한다
다 끝나고, 스택이 남아 있으면 스택의 탑이 내가 만나는 애니까 걔로 답을 하고, 없으면 만나는 애가 없으므로 0이다.
그 후 나도 스택에 들어가면 끝

2589: 보물섬

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

육지와 바다가 지도에 주어질 때, 육지의 가장 최단거리로 간다고 가정할 때 가장 오래 걸리는 거리 구하기

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

int mmap[51][51];
int visited[51][51];
int n, m;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
int ans = 0;

void func(int nowx, int nowy){
    queue<P> q;
    q.push(make_pair(nowx, nowy));
    visited[nowx][nowy] = 0;
    while( q.size() ){
        int x = q.front().first;
        int y = q.front().second;
        int d = visited[x][y];
        q.pop();

        ans = max(ans, d);

        for(int i = 0; i < 4; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if( nx < 0 || n <= nx
               || ny < 0 || m <= ny
               || visited[nx][ny] <= d+1 || mmap[nx][ny] == 0 ) continue;
            visited[nx][ny] = min(visited[nx][ny], d+1);
            q.push(make_pair(nx, ny));
        }
    }

    /*
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if( visited[i][j] == 2501 ) cout << "x" << ' ';
            else cout << visited[i][j] << ' ';
        }
        cout << "\n";
    }
    */
}

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

    cin >> n >> m;

    for(int i = 0; i < n; i++){
        string s;
        cin >> s;
        for(int j = 0; j < m; j++){
            mmap[i][j] = s[j] == 'W' ? 0 : 1;
        }
    }

    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            if( mmap[i][j] == 0 ) continue;
            for(int ii = 0; ii < n; ii++){
                for(int jj = 0; jj < m; jj++){
                    visited[ii][jj] = 2501;
                }
            }
            func(i, j);
            //cout << i << ' ' << j << ' ' << ans << "\n\n";
        }
    }

    cout << ans << endl;

}

간단한 bfs로 다 뒤지면 된다
다음 위치가 지도 범위 내에 있고, 혹시 더 적은 시간으로 이미 방문한 곳인지 확인하고, 육지인지 확인하고 큐에 넣어준다

ex) 백준 예제
x 4 5 x x x x
2 3 4 x x x x
1 x 5 x x x x
0 x 6 x x x x
x 8 7 x x x x
(3, 0)에서 출발, (4, 1)에 도착



굿

댓글남기기