https://codeforces.com/contest/1638

 

Dashboard - Codeforces Round #771 (Div. 2) - Codeforces

 

codeforces.com

 

A. Reverse

더보기

풀이

  • 오름차순으로 되어있을 때 사전 순으로 맨 앞이다.
  • 오름차순 정렬된 상태와 처음으로 같지 않을 때 그 위치에 있어야 할 수가 그 위치에 오도록 reverse 하지 않으면 그렇게 한 것보다 사전 순으로 뒤에 있다.
  • 따라서 그 위치에 오도록 reverse 하는게 사전 순으로 맨 앞이다.

코드

  • 시간복잡도: $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);
        for (auto& e: a) {
            cin >> e;
        }
        vector<int> tmp(a);
        sort(all(tmp));

        for (int i = 0; i < N; ++i) {
            if (a[i] != i + 1) {
                auto it = find(a.begin() + i + 1, a.end(), i + 1);
                reverse(a.begin() + i, it + 1);
                break;
            }
        }
        for (auto& e: a) {
            cout << e << ' ';
        }
        cout << '\n';
    }
}

 

 

B. Odd Swap Sort

더보기

풀이

  • 홀수, 짝수 사이는 자유롭게 스왑가능하다.
  • 홀수, 홀수 이거나 짝수, 짝수 이면 스왑불가능하다.
  • 따라서 operation 후 홀수들간의 위치관계 와 짝수들간의 위치관계는 각각 유지된다.
  • 짝수, 홀수 들이 각각 정렬된 상태이면 전체를 정렬할 수 있다.

코드

  • 시간복잡도: $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<long long> odd, even;

        for (int i = 0; i < N; ++i) {
            int num;
            cin >> num;
            if (num & 1) {
                odd.push_back(num);
            } else {
                even.push_back(num);
            }
        }

        if (is_sorted(all(odd)) && is_sorted(all(even))) {
            cout << "Yes\n";
        } else{
            cout << "No\n";
        }
    }
}

 

 

C. Inversion Graph

더보기

풀이

  • Disjoint set 자료구조에서 각 셋의 최댓값을 루트로 한다.
  • 배열 원소 차례로 순회하면서 이전 set 들의 최댓값들 중 지금 원소보다 큰 값이 있으면 union 한다.

코드

  • 시간복잡도: 아마 $O(NlogN)$

※ 스택으로 연결된 그룹의 min, max 관리하면 $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);
        for (auto& e: a) {
            cin >> e;
        }

        vector<int> p(N + 1, -1);
        function<int(int)> myFind = [&](int n) {
            if (p[n] == -1) return n;
            return p[n] = myFind(p[n]);
        };
        set<int> s;
        auto myUnion = [&](int n1, int n2) {
            int p1 = myFind(n1);
            int p2 = myFind(n2);

            if (p1 == p2) return;
            if (p1 > p2) swap(p1, p2);
            p[p1] = p2;
            s.erase(p1);
        };

        int answer = N;
        s.insert(a[0]);
        for (int i = 1; i < N; ++i) {
            auto it = s.upper_bound(a[i]);
            if (it != s.end()) {
                while (it != s.end()) {
                    myUnion(a[i], *it);
                    --answer;
                    it = s.upper_bound(myFind(a[i]));
                }
            } else {
                s.insert(a[i]);
            }
        }
        cout << answer << '\n';
    }
}

 

D. Big Brush

더보기

풀이

  • 색칠순서를 역순으로 구성한다.
  • 처음에는 4칸이 모두 같은색인 곳을 칠한다.
  • 이전에 칠한곳은 지금칠할 곳을 덮어쓰므로 어떤색이어도 상관없다.
  • 이전에 칠한곳 근처에서 4칸 중 이전에 칠한곳을 제외한 칸들이 모두 같은색이면 칠한다.

코드

  • BFS
  • 시간복잡도: $O(NM)$
#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;
    cin >> N >> M;

    vector<vector<int> > a(N, vector<int> (M));
    vector<vector<int> > b(N, vector<int> (M, 0));

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            cin >> a[i][j];
        }
    }

    queue<tuple<int, int, int> > q;
    auto check = [&](int i, int j) {
        if (i < 0 || i >= N - 1 || j < 0 || j >= M - 1) return 0;
        set<int> color;
        for (int ii = 0; ii < 2; ++ii) {
            for (int jj = 0; jj < 2; ++jj) {
                if (!b[i + ii][j + jj]) {
                    color.insert(a[i + ii][j + jj]);
                }
            }
        }

        if (color.size() == 1) {
            return *color.begin();
        } else {
            return 0;
        }
    };

    vector<vector<int> > visited(N - 1, vector<int> (M - 1, false));
    for (int i = 0; i < N - 1; ++i) {
        for (int j = 0; j < M - 1; ++j) {
            auto c = check(i, j);
            if (c) {
                q.push({i, j, c});
                visited[i][j] = true;
            }
        }
    }

    vector<tuple<int, int, int> > answer;
    int dr[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dc[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    while (q.size()) {
        int cnt = q.size();
            auto [i, j, c] = q.front();
            q.pop();
            answer.push_back({i, j, c});
            b[i][j] = b[i + 1][j] = b[i][j + 1] = b[i + 1][j + 1] = true;
            for (int dir = 0; dir < 8; ++dir) {
                int ni = i + dr[dir];
                int nj = j + dc[dir];
                if (ni < 0 || ni >= N - 1 || nj < 0 || nj >= M - 1 || visited[ni][nj]) continue;
                auto nc = check(ni, nj);
                if (nc) {
                    q.push({ni, nj, nc});
                    visited[ni][nj] = true;
                }
            }
    }

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            if (!b[i][j]) {
                cout << "-1\n";
                return 0;
            }
        }
    }

    reverse(all(answer));
    cout << answer.size() << '\n';
    for (auto [i, j, c]: answer) {
        cout << i + 1 << ' ' << j + 1 << ' ' << c << '\n';
    }
}

 

728x90

+ Recent posts