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

 

2316번: 도시 왕복하기 2

N개의 도시가 P개의 양방향 길로 연결되어 있다. 이석원은 1번 도시와 2번 도시 사이를 오가며 워해머를 한다. 성실한 이석원은 두 도시 사이를 최대한 많이 왔다 갔다 하려 하는데, 이때 한 번 방

www.acmicpc.net

풀이

  • 1, 2번 제외한 정점들은 한번씩만 지날 수 있다 -> 용량 1 인 간선으로 각 정점분할
    • u 의 in 정점 : 2u - 1, out 정점: 2u
    • in -> out 단방향 간선 용량 1
    • 1, 2번 정점은 여러번 지날 수 있어야 하므로 (in -> out) 간선 용량은 400(최대 경로 수) 로 지정
  • u - v : 양방향 간선을 두개의 단방향 간선으로 (u out -> v in, v out -> u in)

정점 모델링

코드

#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

struct Edge {
    int to, c, f;
    Edge* reverse;
    Edge() {
        to = c = f = 0;
        reverse = nullptr; 
    }
    Edge(int to_, int c_) {
        f = 0;
        c = c_;
        to = to_;
        reverse = nullptr;
    }

    int residual() {
        return c - f;
    }
};

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

    int N, P;
    cin >> N >> P;

    vector<vector<Edge*> > adj(2 * N + 1);

    auto makeEdge = [&](int u, int v, int c) {
        auto e1 = new Edge(v, c);
        auto e2 = new Edge(u, 0);
        e1 -> reverse = e2;
        e2 -> reverse = e1;
        adj[u].push_back(e1);
        adj[v].push_back(e2);
    };

    for (int i = 0; i < P; ++i) {
        int u, v;
        cin >> u >> v;
        makeEdge(2 * u, 2 * v - 1, 1);
        makeEdge(2 * v, 2 * u - 1, 1);
    }
    for (int i = 1; i <= N; ++i) {
        int c = 1;
        if (i == 1 || i == 2) c = 400;
        makeEdge(2 * i - 1, 2 * i, c);
    }

    int S = 1 * 2 - 1;
    int T = 2 * 2;
    int answer = 0;

    while (true) {
        vector<Edge*> prev(2 * N + 1, nullptr);
        queue<int> q;
        q.push(S);
        while (q.size()) {
            auto f = q.front();
            q.pop();
            for (auto e: adj[f]) {
                if (prev[e -> to]) continue;
                if (e -> residual() <= 0) continue;
                q.push(e -> to);
                prev[e -> to] = e;
                if (e -> to == T) break;
            }
            if (prev[T]) break;
        }

        if (!prev[T]) break;

        int flow = 1e9;
        for (int cur = T; cur != S; cur = prev[cur] -> reverse -> to) {
            flow = min(flow, prev[cur] -> residual());
        }

        for (int cur = T; cur != S; cur = prev[cur] -> reverse -> to) {
            prev[cur] -> f += flow;
            prev[cur] -> reverse -> f -= flow;
        }
        answer += flow;
    }
    cout << answer << '\n';
}
728x90

'PS > BOJ' 카테고리의 다른 글

백준 9248번: Suffix Array  (0) 2022.02.21
백준 3033번: 가장 긴 문자열  (0) 2022.02.20
백준 13537번: 수열과 쿼리 1  (0) 2022.02.19
백준 1126번: 같은 탑  (0) 2022.02.18
백준 11377번: 열혈강호 3  (0) 2022.02.18

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

 

13537번: 수열과 쿼리 1

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. i j k: Ai, Ai+1, ..., Aj로 이루어진 부분 수열 중에서 k보다 큰 원소의 개수를 출력한다.

www.acmicpc.net

풀이

  • 기본적인 세그먼트 트리에서 노드의 값을 해당 노드 구간의 배열을 정렬된 상태로 가지는 머지 소트 트리를 이용

예제 입력 1의 트리 구성

코드

  • 시간복잡도: $O(NlogN + Mlog^2N)$
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int N;
    cin >> N;

    vector<vector<long long> > t(2 * N);
    for (int i = 0; i < N; ++i) {
        int num;
        cin >> num;
        t[N + i].push_back(num);
    }

    for (int i = N - 1; i >= 1; --i) {
        t[i].resize(t[i << 1 | 1].size() + t[i << 1].size());
        merge(all(t[i << 1 | 1]), all(t[i << 1]), t[i].begin());
    }

    auto query = [&](int l, int r, int k) {
        int ret = 0;
        for (l += N, r += N; l < r; l >>= 1, r >>= 1) {
            if (l & 1) ret += t[l].end() - upper_bound(all(t[l]), k), ++l;
            if (r & 1) --r, ret += t[r].end() - upper_bound(all(t[r]), k);
        }
        return ret;
    };

    int M;
    cin >> M;
    while (M--) {
        int i, j, k;
        cin >> i >> j >> k;
        cout << query(i - 1, j, k) << '\n';
    }
}

 

728x90

'PS > BOJ' 카테고리의 다른 글

백준 3033번: 가장 긴 문자열  (0) 2022.02.20
백준 2316번: 도시 왕복하기 2  (0) 2022.02.20
백준 1126번: 같은 탑  (0) 2022.02.18
백준 11377번: 열혈강호 3  (0) 2022.02.18
백준 19585번: 전설  (0) 2022.02.15

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

 

1126번: 같은 탑

첫째 줄에 조각의 개수 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에 각 조각의 높이가 주어진다. 높이는 500,000보다 작거나 같은 자연수이고, 모든 조각의 높이의 합은 500,000을 넘

www.acmicpc.net

풀이

$dp[i][diff]:$ $i$ 까지 고려해서 쌓은 경우에서 차이가 $diff$ 일 때 더 높은쪽의 높이의 최댓값

dp[i][diff]

※ $i, diff$ 이 불가능한 경우: $dp[i][diff] = -1$

 

$dp[i - 1][j] \neq -1$ 일 때

  1. $i$ 블록 안 쌓는 경우
    • $dp[i][j] = max(dp[i][j], dp[i - 1][j])$
  2. $i$ 블록 쌓는 경우
    1. 높은 쪽에 쌓는 경우
      • $dp[i][j + a[i]] = max(dp[i][j + a[i]], dp[i - 1][j] + a[i])$
    2. 낮은 쪽에 쌓는 경우
      1. $a[i] < j$
        • $dp[i][j - a[i]] = max(dp[i][j - a[i]], dp[i - 1][j])$
      2. $a[i] \geq j$
        • $dp[i][a[i] - j] = max(dp[i][a[i] - j], dp[i - 1][j] + a[i] - j)$

코드

#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int N;
    cin >> N;

    vector<int> a(N);
    vector<vector<int> > dp(N, vector<int> (500001, -1));
    for (int i = 0; i < N; ++i) {
        cin >> a[i];
    }
    
    dp[0][0] = 0;
    dp[0][a[0]] = a[0];
    for (int i = 1; i < N; ++i) {
        for (int j = 0; j <= 500000; ++j) {
            if (dp[i - 1][j] == -1) continue;
            dp[i][j] = max(dp[i][j], dp[i - 1][j]);
            if (j + a[i] <= 500000) dp[i][j + a[i]] = max(dp[i][j + a[i]], dp[i - 1][j] + a[i]);
            if (a[i] < j) {
                dp[i][j - a[i]] = max(dp[i][j - a[i]], dp[i - 1][j]);
            } else {
                dp[i][a[i] - j] = max(dp[i][a[i] - j], dp[i - 1][j] + a[i] - j);
            }
        }
    }
    if (dp[N - 1][0] > 0) {
        cout << dp[N - 1][0] << '\n';
    } else {
        cout << "-1\n";
    }
}
728x90

'PS > BOJ' 카테고리의 다른 글

백준 2316번: 도시 왕복하기 2  (0) 2022.02.20
백준 13537번: 수열과 쿼리 1  (0) 2022.02.19
백준 11377번: 열혈강호 3  (0) 2022.02.18
백준 19585번: 전설  (0) 2022.02.15
백준 4225번: 쓰레기 슈트  (0) 2022.02.12

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

 

11377번: 열혈강호 3

첫째 줄에 직원의 수 N과 일의 개수 M, 일을 2개할 수 있는 직원의 수 K가 주어진다. (1 ≤ N, M ≤ 1,000, 1 ≤ K ≤ N) 둘째 줄부터 N개의 줄의 i번째 줄에는 i번 직원이 할 수 있는 일의 개수와 할 수 있

www.acmicpc.net

 

풀이1. Maximum flow(에드몬드 카프)

최대 K 명까지 일을 두개 할 수 있다는 것을 Source 에서 용량 K 로 이어진 추가 노드를 구성함으로써 구현

네트워크 모델링

코드1.

  • 단방향 플로우에서 역방향 간선의 capacity = 0 으로 해야함에 주의
  • 시간복잡도: $min(O((V + E)f), O(VE^2)) \to O((V + E)(V + K))$ 
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
struct Edge {
    int to, c, f;
    Edge* reverse;

    Edge() {
        to = 0;
        c = 0;
        f = 0;
        reverse = nullptr;
    }
    int residual() {
        return c - f;
    }
};

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

    int N, M, K;
    cin >> N >> M >> K;
    vector<vector<Edge*> > adj(N + M + 3);
    auto makeEdge = [&](int n1, int n2, int cc) {
        auto e1 = new Edge();
        auto e2 = new Edge();

        e1 -> to = n2;
        e1 -> reverse = e2;
        e1 -> c = cc;
        e2 -> to = n1;
        e2 -> reverse = e1;

        adj[n1].push_back(e1);
        adj[n2].push_back(e2);
    };

    int S = 0, T = N + M + 1, X = N + M + 2;

    makeEdge(S, X, K);
    for (int i = 1; i <= N; ++i) {
        int num;
        cin >> num;
        makeEdge(S, i, 1);
        makeEdge(X, i, 1);
        while (num--) {
            int w;
            cin >> w;
            makeEdge(i, N + w, 1);
        }
    }
    for (int i = 1; i <= M; ++i) {
        makeEdge(N + i, T, 1);
    }

    while (true) {
        vector<Edge*> prev(N + M + 3, nullptr);
        queue<int> q;
        q.push(S);
        while (!q.empty()) {
            auto f = q.front();
            q.pop();

            for (auto e: adj[f]) {
                if (e -> residual() <= 0) continue;
                if (prev[e -> to]) continue;
                q.push(e -> to);
                prev[e -> to] = e;
                if (e -> to == T) break;
            }
            if (prev[T]) break;
        }

        if (!prev[T]) break;

        int flow = 1e9;
        for (auto cur = T; cur != S; cur = prev[cur] -> reverse -> to) {
            flow = min(flow, prev[cur] -> residual());
        }
        for (auto cur = T; cur != S; cur = prev[cur] -> reverse -> to) {
            prev[cur] -> f += flow;
            prev[cur] -> reverse -> f -= flow;
        }
    }

    int answer = 0;
    for (auto e: adj[T]) {
        answer += e -> reverse -> f;
    }
    cout << answer << '\n';
}

풀이2. Bipartite matching

직원당 두개의 노드를 만들고 그룹 두개로 나눠서 한그룹에서 이분매칭 후 두번째 그룹에서 K번 이하 이분매칭

코드2. 

  • 시간복잡도: $O(VE)$
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

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

    vector<int> A(2 * N + 1, 0), B(M + 1, 0);
    vector<vector<int> > adj(2 * N + 1);

    for (int i = 1; i <= N; ++i) {
        int num;
        cin >> num;
        while (num--) {
            int m;
            cin >> m;
            adj[2 * i - 1].push_back(m);
            adj[2 * i].push_back(m);
        }
    }

    vector<int> visited(2 * N + 1, false);
    function<bool(int)> f = [&](int a) {
        visited[a] = true;
        for (auto b: adj[a]) {
            if (!B[b] || (!visited[B[b]] && f(B[b]))) {
                A[a] = b;
                B[b] = a;
                return true;
            }            
        }
        return false;
    };

    int match = 0;
    for (int i = 1; i <= 2 * N; i += 2) {
        if (!A[i]) {
            fill(all(visited), false);
            if (f(i)) ++match;
        }
    }
    int matched2 = 0;
    for (int i = 2; i <= 2 * N && matched2 < K; i += 2) {
        if (!A[i]) {
            fill(all(visited), false);
            if (f(i)) ++matched2;
        }
    }

    cout << match + matched2 << '\n';
}

 

728x90

'PS > BOJ' 카테고리의 다른 글

백준 2316번: 도시 왕복하기 2  (0) 2022.02.20
백준 13537번: 수열과 쿼리 1  (0) 2022.02.19
백준 1126번: 같은 탑  (0) 2022.02.18
백준 19585번: 전설  (0) 2022.02.15
백준 4225번: 쓰레기 슈트  (0) 2022.02.12

https://codeforces.com/contest/1637

 

Dashboard - Codeforces Global Round 19 - Codeforces

 

codeforces.com

 

A. Sorting Parts

  • 임의의 원소에 대해서 그 원소를 포함하는 앞부분, 그 원소 뒷부분 각각 non-decreasing order 로 정렬한 뒤 전체배열이 non-decreasing 정렬되어있게 만들 수 있는지 판단하는 문제
  • a[i] > a[i + 1] 이면 a[i] 를 기준으로 잡으면 만들 수 있다. 그런 경우가 없으면 불가능.

코드

더보기
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int TC; cin >> TC;
    while (TC--) {
        int N;
        cin >> N;
        vector<int> a(N);
        for (auto& e: a) {
            cin >> e;
        }

        auto sorted = is_sorted(all(a));
        if (sorted) {
            cout << "NO\n";
        } else {
            cout << "YES\n";
        }
    }
}

 


B. MEX and Array

문제요약

배열 b1, ..., bk 를 c 개의 segment로 나누는 partition에 대해

cost of partition = c + sum(mex(segment[i])) = sum(1 + mex(segment[i]))

value of array = max(cost of partition)

일 때,

입력 배열의 모든 subsegment 에 대해 value 의 합을 구해라

풀이1.

가정: 길이 k 의 segment b1,..., bk 의 cost 기여분은 segment b1, segment b2, ... segment bk 의 cost 기여분의 합보다 작거나 같다. 즉, 세그먼트를 길이 1 segment 로 나눌때 cost 가 최대이다.

 

증명

  1. b1...bk 중 0 이 있을 때
  2. b1...bk 중 0 이 없을 때

1번 경우.

b1...bk 의 cost = 1 + mex <= 1 + k (k개 원소이므로 mex 최댓값이 k)

길이 1로 파티션 했을 때 cost = k + (zerocnt) * 1

이 때 zerocnt >= 1 이므로 길이 1 파티션의 cost 가 더 크다.

 

2번 경우.

b1...bk의 cost = 1 + 0 = 1

길이 1로 파티션 했을 때 cost = k + 0

k >= 1 일 때 길이 1 파티션 cost 가 크거나 같다.

 

어떤 segment 의 cost 보다 그 segment 를 길이 1 파티션했을때가 cost 가 더 크거나 같다는 것을 증명했다.

 

segment 를 파티션하는 방법중 cost 가 제일 큰 파티션방법에 길이가 1 보다 큰 segment 가 있다고 가정하면 

그 segment 의 cost 는 그 segment 를 1로 파티션한 cost 보다 작거나 같으므로 cost 가 최대라는 것에 모순.

따라서 segment 를 파티션하는 방법중 cost 가 제일큰 파티션방법은 길이 1로 파티션하는 것이다.

 

코드

  • sum(value of all subsegment) = sum(subsegment length + 1 * zerocnt)
  • 시간복잡도: O(N) 
더보기

 

#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int TC; cin >> TC;
    while (TC--) {
        int N;
        cin >> N;
        vector<int> a(N);
        long long answer = 0;
        for (int i = 1; i <= N; ++i) {
            answer += 1LL * i * (N - i + 1);
        }

        for (int i = 0; i < N; ++i) {
            cin >> a[i];
            if (a[i] == 0) {
                answer += 1LL * (i + 1) * (N - i);
            }
        }
        cout << answer << '\n';
    }
}

 

 

풀이2.

dp[l][r] = value of arr[l...r]

          = max(1 + mex(arr[l...r]), max(dp[l][l + c] + dp[l + c + 1][r]))

 

 

코드

  • 시간복잡도: O(N^4)
더보기
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int TC; cin >> TC;
    while (TC--) {
        int N;
        cin >> N;
        vector<int> a(N);
        for (auto& e: a) {
            cin >> e;
        }

        auto getMEX = [&](vector<int> arr) {
            sort(all(arr));
            int mex = 0;
            for (auto e: arr) {
                if (e == mex) {
                    ++mex;
                } else {
                    break;
                }
            }
            return mex;
        };
        vector<vector<long long> > dp(N, vector<long long> (N, -1));
        function<long long(int, int)> f = [&](int l, int r) {
            long long& ret = dp[l][r];

            if (ret != -1) {
                return ret;
            }

            vector<int> tmp(a.begin() + l, a.begin() + r + 1);
            ret = 1 + getMEX(tmp);

            for (int i = l; i < r; ++i) {
                ret = max(ret, f(l, i) + f(i + 1, r));
            }
            return ret;
        };

        long long answer = 0;
        for (int l = 0; l < N; ++l) {
            for (int r = l; r < N; ++r) {
                answer += f(l, r);
            }
        }
        cout << answer << '\n';
    }
}

C. Andrew and Stones

문제요약

operation:

1 <= i < j < k <=n 인  i, j, k 선택

j 에서 i, j 로 1개씩 옮김

operation 최소로 사용해서 양 끝말고는 all 0 만들기

 

풀이

odd: o, even: e

처음 끝 사이 배열에 대해서

 

  • 길이 1 이고 홀수면 불가능
  • 짝수가 하나라도 껴있는 꼴이면 가능
    • e o o o -> 0 e o o -> ... -> 0 0 0 0
    • 모두 홀수인데 3 이상인게 하나라도 있으면 위의 꼴로 만들 수 있음
      •  o 3 o -> e o e -> ... -> 0 0 0
  • 필요한 operation 횟수 >= sum(ceil(a[i] / 2))

 

코드

더보기
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

    int TC; cin >> TC;
    while (TC--) {
        int N;
        cin >> N;
        vector<int> a(N);
        for (auto& e: a) {
            cin >> e;
        }

        if ((N == 3 && a[1] & 1) || (*max_element(a.begin() + 1, a.end() - 1) == 1)) {
            cout << "-1\n";
            continue;
        }
        long long answer = 0;
        for (int i = 1; i < N - 1; ++i) {
            answer += a[i] + 1 >> 1;
        }
        cout << answer << '\n';
    }
}

D. Yet Another Minimization Problem

풀이

수식 정리하면

앞 두 항의 합은 a, b 원소 스왑해도 일정. totalcost 는 뒤 두항에 따라 달라짐

sumB = totalSum - sumA

원소 값의 범위가 1~100 이고 갯수는 100 이므로 sumA 가 될 수 있는 최댓값은 100 * 100

dp[i][sum]: operation 후 가능한 a 에 대하여 i 열까지 합이 sum 이 가능하면 true

dp[i][sum] = dp[i - 1][sum - a[i]] || dp[i - 1][sum - b[i]]

 

코드

더보기
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

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

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

        if (N == 1) {
            int a, b;
            cin >> a >> b;
            cout << "0\n";
            continue;
        }

        int maxSum = 100 * 100;
        vector<long long> a(N), b(N);
        long long answer = 0;
        long long totalSum = 0;
        for (int i = 0; i < N; ++i) {
            cin >> a[i];
            answer += 1LL * (N - 2) * a[i] * a[i];
            totalSum += a[i];
        }
        for (int i = 0; i < N; ++i) {
            cin >> b[i];
            answer += 1LL * (N - 2) * b[i] * b[i];
            totalSum += b[i];
        }

        vector<vector<int> > dp(N, vector<int> (maxSum + 1, false));
        dp[0][a[0]] = dp[0][b[0]] = true;
        for (int i = 1; i < N; ++i) {
            for (int j = maxSum; j >= 0; --j) {
                if (j - a[i] >= 0) dp[i][j] |= dp[i - 1][j - a[i]];
                if (j - b[i] >= 0) dp[i][j] |= dp[i - 1][j - b[i]];
            }
        }

        long long tmp = 1e18;
        for (int i = 0; i <= maxSum; ++i) {
            if (dp[N - 1][i]) {
                tmp = min(tmp, 1LL * i * i + 1LL * (totalSum - i) * (totalSum - i));
            }
        }
        cout << answer + tmp << '\n';
    }
}

E. Best Pair

cntX, cntY (cntY <= cntX), x 에 대해 y는 가장 큰 값(x != y && bad pairs 가 아닌) 만 보면 됨

 

코드

더보기
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int TC; cin >> TC;
    while (TC--) {
        int N, M;
        cin >> N >> M;
        map<int, int> cnt;
        vector<long long> a(N);
        for (auto& e: a) {
            cin >> e;
            cnt[e]++;
        }

        set<pair<int, int> > bad;
        for (int i = 0; i < M; ++i) {
            int x, y;
            cin >> x >> y;
            bad.insert({x, y});
            bad.insert({y, x});
        }
        long long answer = 0;

        set<int> cntSet;
        vector<vector<int> > v(N + 1);
        for (auto [num, cnt_]: cnt) {
            cntSet.insert(cnt_);
            v[cnt_].push_back(num);
        }
        for (auto& e: v) {
            reverse(all(e));
        }

        for (auto rit = cntSet.rbegin(); rit != cntSet.rend(); ++rit) {
            for (auto rit2 = rit; rit2 != cntSet.rend(); ++rit2) {
                for (auto x: v[*rit]) {
                    for (auto y: v[*rit2]) {
                        if (x != y && bad.find({x, y}) == bad.end()) {
                            answer = max(answer, 1LL * (x + y) * (*rit + *rit2));
                            break;
                        }
                    }
                }
            }
        }

        cout << answer << '\n';
    }
}
728x90

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

 

19585번: 전설

Sogang ICPC Team에는 색상 이름과 닉네임의 순서로 이여서 팀명을 지으면 ICPC 리저널에서 수상할 수 있다는 전설이 있다. 색상 이름들과 닉네임들이 주어질 때, Q개의 팀에 대해 다음 리저널에서 수

www.acmicpc.net

풀이

  1. 입력받은 팀명의 앞에서부터 color 와 매치되는 인덱스들 체크
  2. 팀명의 뒤에서부터 name 과 매치되는 인덱스들 체크
  3. color 매치되는 인덱스 + 1 = name 과 매치되는 인덱스 이면 color + name 팀명

 

코드

  • MLE 피하기 위해 map 사용한 Trie 구조체 사용
#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

struct Trie {
    bool isTerminal;
    map<char, Trie*> children;
    Trie() {
        isTerminal = false;
    }

    ~Trie() {
        for (auto& e: children) {
            delete e.second;
        }
        children.clear();
    }
};

void insert(Trie* root, string key) {
    Trie* tmp = root;
    for (auto e: key) {
        if (tmp -> children.find(e) == tmp -> children.end()) {
            tmp -> children[e] = new Trie();
        }
        tmp = tmp -> children[e];
    }
    tmp -> isTerminal = true;
}
void insert_rev(Trie* root, string key) {
    Trie* tmp = root;
    for (int i = key.size() - 1; i >= 0; --i) {
        if (tmp -> children.find(key[i]) == tmp -> children.end()) {
            tmp -> children[key[i]] = new Trie();
        }
        tmp = tmp -> children[key[i]];
    }
    tmp -> isTerminal = true;
}

void check(Trie* root, vector<int>& checked, string& key) {
    auto cur = root;
    for (int i = 0; i < key.size(); ++i) {
        if (cur -> children.find(key[i]) == cur -> children.end()) return;
        cur = cur -> children[key[i]];        
        if (cur -> isTerminal) checked[i] = true;
    }
}
void check_rev(Trie* root, vector<int>& checked, string& key) {
    auto cur = root;
    for (int i = key.size() - 1; i >= 0; --i) {
        if (cur -> children.find(key[i]) == cur -> children.end()) return;
        cur = cur -> children[key[i]];
        if (cur -> isTerminal) checked[i] = true;
    }
}

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

    int N, C, Q;
    cin >> C >> N;

    Trie* color = new Trie();
    Trie* name = new Trie();
    for (int i = 0; i < C; ++i) {
        string s;
        cin >> s;
        insert(color, s);
    }
    for (int i = 0; i < N; ++i) {
        string s;
        cin >> s;
        insert_rev(name, s);
    }

    cin >> Q;
    while (Q--) {
        string ss;
        cin >> ss;
        vector<int> checked1(ss.size(), 0);
        vector<int> checked2(ss.size(), 0);
        check(color, checked1, ss);
        check_rev(name, checked2, ss);
        bool yes = false;
        for (int i = 0; i < ss.size() - 1; ++i) {
            if (checked1[i] == 1 && checked2[i + 1] == 1) {
                yes = true;
                break;
            }
        }
        if (yes) {
            cout << "Yes\n";
        } else {
            cout << "No\n";
        }
    }
}
728x90

'PS > BOJ' 카테고리의 다른 글

백준 2316번: 도시 왕복하기 2  (0) 2022.02.20
백준 13537번: 수열과 쿼리 1  (0) 2022.02.19
백준 1126번: 같은 탑  (0) 2022.02.18
백준 11377번: 열혈강호 3  (0) 2022.02.18
백준 4225번: 쓰레기 슈트  (0) 2022.02.12

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

 

4225번: 쓰레기 슈트

선영이는 쓰레기를 편하게 버리기 위해서 빌딩에 쓰레기 슈트를 만들었다. 쓰레기 슈트는 빌딩에 설치할 수 있는 속이 빈 튜브다. 튜브로 쓰레기를 떨어뜨리면, 쓰레기는 지하실까지 떨어지게

www.acmicpc.net

 

- 다각형이 통과하는데 필요한 최소 슈트 너비는 그 다각형의 점들을 포함하는 볼록 다각형, 즉 convex hull 이 통과하는데 필요한 최소 슈트 너비와 같다

- 볼록 다각형의 한 변이 슈트 한변에 접해서 통과한다고 할 때 필요한 최소 슈트 너비는 그 변에서 가장 멀리 떨어진 점과의 거리와 같다.


1. convex hull 이루는 점 집합 구하기

2. 각 변에 대해서 가장 멀리 떨어진 점까지의 거리들 중 최솟값이 답

  2-1. 변 p1p2 와 점 p3 거리는 외적(p1p2, p2p3)크기 / p1p2길이

  2-2. 올림할 때 소수점 셋째 자리이하가 0 보다 큰지 비교해서 올림하면 틀릴 수 있음, 1e-12 와 비교

 

#include <bits/stdc++.h>

using namespace std;

#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int caseNum = 1;
    int N;

    auto cp = [&](pair<long double, long double> p1, pair<long double, long double> p2, pair<long double, long double> p3) {
        auto ret = (p2.first - p1.first) * (p3.second - p2.second) - (p2.second - p1.second) * (p3.first - p2.first);
        return ret;
    };
    
    pair<long double, long double> base;
    auto cmp = [&](pair<long double, long double> p1, pair<long double, long double> p2) {
        auto cp_ = cp(base, p1, p2);
        if (cp_ != 0) {
            return cp_ > 0;
        }
        return (base.first - p1.first) * (base.first - p1.first) + (base.second - p1.second) * (base.second - p1.second) < (base.first - p2.first) * (base.first - p2.first) + (base.second - p2.second) * (base.second - p2.second);
    };

    while (cin >> N && N) {

        vector<pair<long double, long double> > p(N);
        for (int i = 0; i < N; ++i) {
            cin >> p[i].first >> p[i].second;
        }

        swap(p[0], *min_element(all(p)));

        base = p[0];

        sort(all(p), cmp);

        stack<pair<long double, long double> > st;
        st.push(p[0]);
        st.push(p[1]);
        for (int i = 2; i < N; ++i) {
            auto p2 = st.top(); st.pop();
            auto p1 = st.top();
            auto p3 = p[i];

            auto cp_ = cp(p1, p2, p3);
            while (cp_ < 0) {
                p2 = p1;
                st.pop(); p1 = st.top();
                cp_ = cp(p1, p2, p3);
            }

            if (cp_ > 0) {
                st.push(p2);
                st.push(p3);
            } else {
                //  cp_ = 0
                st.push(p3);
            }
        }

        vector<pair<long double, long double> > convexHull(st.size());
        while (st.size()) {
            convexHull[st.size() - 1] = st.top();
            st.pop();
        }

        long double answer = 1e18;
        
        for (int i = 0; i < convexHull.size(); ++i) {
            auto p1 = convexHull[i];
            auto p2 = convexHull[(i + 1) % (convexHull.size())];
            long double maxDist = 0;
            long double p1p2 = sqrtl((p1.first - p2.first) * (p1.first - p2.first) + (p1.second - p2.second) * (p1.second - p2.second));
            for (int j = 0; j < convexHull.size(); ++j) {
                auto p3 = convexHull[j];
                auto cp_ = abs(cp(p1, p2, p3));
                maxDist = max(maxDist, cp_ / p1p2);
            }
            answer = min(answer, maxDist);
        }

        answer *= 100;
        if (answer - (long long)answer > 1e-12) {
            answer += 1;
            answer = (long long)answer;
        }
        answer /= 100;
        cout.precision(2);
        cout << fixed;
        cout << "Case " << caseNum++ << ": " << answer << '\n';
    }
}

 

728x90

'PS > BOJ' 카테고리의 다른 글

백준 2316번: 도시 왕복하기 2  (0) 2022.02.20
백준 13537번: 수열과 쿼리 1  (0) 2022.02.19
백준 1126번: 같은 탑  (0) 2022.02.18
백준 11377번: 열혈강호 3  (0) 2022.02.18
백준 19585번: 전설  (0) 2022.02.15

+ Recent posts