https://atcoder.jp/contests/abc241/tasks

 

Tasks - AtCoder Beginner Contest 241(Sponsored by Panasonic)

AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

atcoder.jp

 

A - Digit Machine

더보기

풀이

  • 배열 a 를 함수로 생각해서 세번 적용

코드

#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 = 10;
    vector<int> a(N);
    for (auto& e: a) {
        cin >> e;
    }

    cout << a[a[a[0]]] << '\n';
}

 

B - Pasta

더보기

풀이

  • 멀티셋에 가진 누들 길이 다 넣고 플랜 진행하면서 없으면 No

코드

  • 시간복잡도: $O(NlogN + MlogN)$
#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<int> a(N), b(M);
    multiset<int> s;
    for (auto& e: a) {
        cin >> e;
        s.insert(e);
    }
    for (auto& e: b) {
        cin >> e;
        auto it = s.find(e);
        if (it == s.end()) {
            cout << "No\n";
            return 0;
        }

        s.erase(it);
    }

    cout << "Yes\n";

}

 

C - Connect 6

더보기

풀이

  • 한 칸에 대해서, 그 칸을 시작으로 8방향에 대해서, 6칸 중 # 이 네칸이상이면 그 칸에서 그 방향으로 최대 2번 칠해서 6개 연속만들기 가능

코드

  • 시간복잡도: $O(N^2*8*6)$
#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<string> a(N);
    for (auto& e: a) {
        cin >> e;
    }

    int dr[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dc[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

    auto check = [&](int r, int c) {
        for (int dir = 0; dir < 8; dir++) {
            int rr = r + dr[dir] * 5;
            int cc = c + dc[dir] * 5;
            if (rr < 0 || rr >= N || cc < 0 || cc >= N) continue;
            int cnt = 0;
            for (int k = 0; k < 6; ++k) {
                int nr = r + dr[dir] * k;
                int nc = c + dc[dir] * k;
                cnt += a[nr][nc] == '.';
            }
            if (cnt <= 2) return true;
        }
        return false;
    };
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (check(i, j)) {
                cout << "Yes\n";
                return 0;
            }
        }
    }
    cout << "No\n";
}

 

D - Sequence Query

더보기

풀이

  • 멀티셋으로 관리
  • 1 쿼리 
    • 멀티셋에 삽입
  • 2 쿼리
    • lower bound 부터 최대 k 번 뒤로 iterate
  • 3 쿼리
    • upper bound 의 prev 부터 최대 k 번 앞으로 iterate 

코드

  • 시간복잡도: $O(QlogQk)$
#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 Q;
    cin >> Q;

    multiset<long long> a;

    while (Q--) {
        long long q, x, k;
        cin >> q >> x;
        if (q == 1) {
            a.insert(x);
        } else if (q == 2) {
            cin >> k; 
            auto it = a.upper_bound(x);
            if (it == a.begin()) {
                cout << "-1\n";
                continue;
            }
            it = prev(it);
            while (true) {
                if (--k == 0) {
                    cout << *it << '\n';
                    break;
                }
                if (it == a.begin()) break;
                it = prev(it);
            }
            if (k) {
                cout << "-1\n";
                continue;
            }
        } else {
            cin >> k;
            auto it = a.lower_bound(x);
            if (it == a.end()) {
                cout << "-1\n";
                continue;
            }
            while (true) {
                if (it == a.end()) break;
                if (--k == 0) {
                    cout << *it << '\n';
                    break;
                }
                it = next(it);
            }
            if (k) {
                cout << "-1\n";
                continue;
            }
        }
    }
}

 

E - Putting Candies

더보기

풀이

  • ans[i]: i 번후 접시위 사탕 수라고 정의하면
  • $ans[i] % N == ans[i + p] % N$ 인 $1 <= p <= N$ 이 존재
  • $ans[i] % N$ 은 그 때 $p$ 주기를 갖는다, 즉 더해지는 수가 $p$ 주기를 가지고 반복된다

코드

  • 시간복잡도: $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);

    long long N, K;
    cin >> N >> K;
    vector<long long> a(N);
    for (auto& e: a) {
        cin >> e;
    }

    vector<long long> v(N + 1, 0), v2(N + 1, 0), cnt(N, 0);
    cnt[0] = 1;

    long long idx = -1, p = -1;
    for (int i = 1; i <= N; ++i) {
        v[i] = v[i - 1] + a[v2[i - 1]];
        v2[i] = v[i] % N;
        
        if (++cnt[v2[i]] == 2) {
            auto it = find(v2.begin(), v2.begin() + i, v2[i]);
            idx = it - v2.begin();
            p = i - idx;
            break;
        }
    }

    long long answer = 0;
    if (K <= idx) {
        answer = v[K];
    } else {
        K -= idx;
        answer += v[idx] + (K / p) * (v[idx + p] - v[idx]);
        K %= p;
        for (int i = 0; i < K; ++i) {
            answer += a[v2[idx + i]];
        }
    }

    assert(p >= 1);

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

 

728x90

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

[앳코더] AtCoder Beginner Contest 240(비기너 240) 풀이  (0) 2022.02.22

문제링크

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

 

16978번: 수열과 쿼리 22

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. 1 i v: Ai = v로 변경한다. 2 k i j: k번째 1번 쿼리까지 적용되었을 때, Ai, Ai+1, ..., Aj의 합을 출력한다.

www.acmicpc.net

풀이

  • 구간합 쿼리의 처리 순서를 적용된 업데이트 쿼리 개수에 대해 오름차순으로 처리한다.
  • 각 구간합 쿼리에 대해 지금까지 적용된 업데이트 쿼리개수 보다 적용해야될 업데이트쿼리 개수가 많으면 진행시켜서 구간합을 구한다.

코드

  • 시간복잡도: $O(MlogM + MlogN)$
#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<long long> a(N), t(2 * N, 0);

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

    for (int i = N - 1; i >= 1; --i) {
        t[i] = t[i << 1] + t[i << 1 | 1];
    }

    auto sum = [&](int l, int r) {
        long long ret = 0;
        for (l += N, r += N; l < r; l >>= 1, r >>= 1) {
            if (l & 1) ret += t[l++];
            if (r & 1) ret += t[--r];
        }
        return ret;
    };

    auto update = [&](int p, long long val) {
        for (t[p += N] = val; p > 1; p >>= 1) {
            t[p >> 1] = t[p] + t[p ^ 1];
        }
    };

    int M;
    cin >> M;
    vector<pair<int, long long> > q1;
    map<int, vector<tuple<int, int, int> > > q2;

    for (int i = 0; i < M; ++i) {
        long long a, b, c, d;
        cin >> a;
        if (a == 1) {
            cin >> b >> c;
            --b;
            q1.push_back({b, c});
        } else {
            cin >> b >> c >> d;
            --c; --d;
            q2[b].push_back({i, c, d});
        }
    }

    int done = -1;
    vector<pair<int, long long> > answer;
    for (auto it = q2.begin(); it != q2.end(); ++it) {
        for (int i = done + 1; i < it -> first; ++i) {
            update(q1[i].first, q1[i].second);
        }

        done = it -> first - 1;

        for (auto [i, l, r]: it -> second) {
            answer.push_back({i, sum(l, r + 1)});
        }
    }

    sort(all(answer));
    
    for (auto e: answer) {
        cout << e.second << '\n';
    }
}
728x90

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

백준 13263번: 나무 자르기  (0) 2022.03.06
백준 4008번: 특공대  (0) 2022.03.06
백준 13548번: 수열과 쿼리 6  (0) 2022.02.28
백준 1420번: 학교 가지마!  (0) 2022.02.26
백준 10254번: 고속도로  (0) 2022.02.26

셀레니움으로 프로그램을 만들다보면 웹페이지에서 자바스크립트에 의해 html 태그가 빠르게 생겼다 없어지는 태그를 이용해야할 때가 있다.

어떤 작업을 로딩이미지나 로딩바가 없어지면 실행해야 하는 경우가 그 예가 되겠다.

 

로딩이미지나 로딩바와 같은 경우 웹사이트에서 데이터를 받는 시간동안에 띄워주는 것이므로 크롬의 네트워크 속도를 조절해주면 태그 정보를 얻고도 남을만큼 충분히 오랫동안 그 태그를 보이는 상태로 만들 수 있다.

 

크롬에서 네트워크 속도 조절은 F12 를 누르면 뜨는 개발자 도구 창의 Network 탭의 Throttling 에서 바꿀 수 있다.

기본적으로 주어진 프리셋말고도 Add... 부분을 눌러서 다운로드속도, 업로드속도, 지연시간 을 커스터마이징할 수 있다. 

 

크롬 개발자도구 창 사진
크롬 개발자도구 창

 

기본적으로 주어진 프리셋의 설정(download, upload, Latency)은 다음과 같다.

  • Fast 3G: 1.6mb/s, 750kb/s, 562.5ms
  • Slow 3G: 500kb/s, 500kb/s, 2000ms
  • Offline: 0, 0, 0

 

728x90

문제링크

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

 

13548번: 수열과 쿼리 6

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. i j: Ai, Ai+1, ..., Aj에 가장 많이 등장하는 수가 몇 번 등장했는지 출력한다.

www.acmicpc.net

풀이

  • 업데이트 쿼리 없으므로 모스 알고리즘 사용
  • 쿼리 시작 끝 옮기면서 원소를 추가하고 제외할 때 원소의 개수 cnt 배열과, cnt 배열의 cnt 즉 그 cnt를 가진 수의 종류의 개수를 나타내는 ccnt 배열을 관리한다.
  • 추가할 때
    •  지금 가진 개수 최대값보다 추가한 원소의 개수가 더 많아지면 갱신
  • 제외할 때
    1. 지금 제외하는 수가 원래 제일 많았던 수인 경우
      • 제외하기전 그 수 cnt 가 최대였고 그 수 한종류만 있었다면 (ccnt = 1) 지금 제외하는 수 cnt 따라감
      • ccnt 가 1 이상이었다면 그대로 유지
    2. 지금 제외하는 수가 제일 많은 수가 아닌 경우
      • 원래 최대 수 유지

 

코드

  • 시간복잡도: $O(MlogM + (N + M)\sqrt 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 N;
    cin >> N;
    vector<int> a(N);
    for (auto& e: a) {
        cin >> e;
    }
    
    int M;
    cin >> M;
    vector<tuple<int, int, int> > query(M);
    for (int i = 0; i < M; ++i) {
        int l, r;
        cin >> l >> r;
        query[i] = {l - 1, r - 1, i};
    }
    int sqrtN = sqrt(N);

    auto cmp = [&](tuple<int, int, int>& t1, tuple<int, int, int>& t2) {
        return get<0>(t1) / sqrtN < get<0>(t2) / sqrtN || (get<0>(t1) / sqrtN == get<0>(t2) / sqrtN && get<1>(t1) < get<1>(t2));
    };

    sort(all(query), cmp);

    vector<int> cnt(1e5 + 1, 0);
    vector<int> ccnt(N + 1, 0);
    int l = 1;
    int r = 0;
    
    int maxCnt = 0;

    auto include = [&](int num) {
        --ccnt[cnt[num]];
        ++cnt[num];
        ++ccnt[cnt[num]];
        maxCnt = max(maxCnt, cnt[num]);
    };
    auto exclude = [&](int num) {
        --ccnt[cnt[num]];
        --cnt[num];
        ++ccnt[cnt[num]];
        if (!ccnt[maxCnt]) {
            maxCnt = cnt[num];
        }
    };

    vector<int> answer(M);
    for (auto& [i, j, ai]: query) {
        while (i < l) include(a[--l]);
        while (i > l) exclude(a[l++]);
        while (j < r) exclude(a[r--]);
        while (j > r) include(a[++r]);
        answer[ai] = maxCnt;
    }
    for (auto& e: answer) {
        cout << e << '\n';
    }
}
728x90

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

백준 4008번: 특공대  (0) 2022.03.06
백준 16978번: 수열과 쿼리 22  (0) 2022.03.02
백준 1420번: 학교 가지마!  (0) 2022.02.26
백준 10254번: 고속도로  (0) 2022.02.26
백준 13547번: 수열과 쿼리 5  (0) 2022.02.25

https://codeforces.com/contest/1642

 

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

 

codeforces.com

 

A. Hard Way

더보기

풀이

  • $y = 0$ 에 도달할 수 없는 점이 존재 하려면 세 점중 y 값이 최소가 아닌 두 점이 이루는 변이 x 축과 평행해야 하고 그 변의 길이가 답이 된다

코드

#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--) {

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

        if (p[0].second > p[1].second) swap(p[0], p[1]);
        if (p[0].second > p[2].second) swap(p[0], p[2]);

        long double answer = 0.0;

        if (p[1].second == p[2].second) {
            answer = abs(p[1].first - p[2].first);
        }

        cout.precision(9);
        cout << fixed << answer << '\n';
    }
}

 

B. Power Walking

더보기

풀이

  • $k = n$ 일 때 힘의 합은 $k$
  • $k = n - 1$ 일 때 서로 다른 두개를 합치면 합은 이전 합과 같고, 같은 두개 합치면 이전합 + 1 
  • 같은 게 있으면 같은 것들 부터 합치자

코드

#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;
        map<int, int> a;
        for (int i = 0; i < N; ++i) {
            int num;
            cin >> num;
            ++a[num];
        }

        int d = 0;
        for (auto [num, cnt]: a) {
            if (cnt >= 2) d += cnt - 1;
        }

        vector<int> answer;
        int k = N;
        for (int i = 0; i < N; ++i) {
            if (d) {
                answer.push_back(k);
                --k;
                d--;
            } else {
                answer.push_back(k);
            }
        }

        reverse(all(answer));

        for (auto e:answer) {
            cout << e << ' ';
        }
        cout << '\n';
        
    }
}

 

C. Great Sequence

더보기

풀이

  • 제일 큰 distinct 원소부터 매칭이 되면 넘어가고 수를 추가해야되면 그 수만큼 추가해준다

코드

  • 시간복잡도: $O(NlogN)$
#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--) {
        long long N, X;
        cin >> N >> X;
        map<long long, long long> m;
        for (int i = 0; i < N; ++i) {
            int num;
            cin >> num;
            ++m[num];
        }

        int answer = 0;
        for (auto rit = m.rbegin(); rit != m.rend(); ++rit) {
            if (rit -> second == 0) continue;
            if (rit -> first % X == 0) {
                auto it = m.lower_bound(rit -> first / X);
                if (it != m.end() && it -> first == rit -> first / X && it -> second > 0) {
                    int tmp = min(rit -> second, it -> second);
                    it -> second -= tmp;
                    rit -> second -= tmp;
                }

                if (rit -> second > 0) {
                  answer += rit -> second;
                  rit -> second = 0;
                } 
            } else {
                answer += rit -> second;
            }
        }
        cout << answer << '\n';
    }
}

 

D. Repetitions Decoding

더보기

풀이

  • operation 해도 각 문자들의 parity 가 유지되므로 홀수 개수인 문자가 존재하면 불가능하다
  • 문자열 $c_1c_2c_3...$ 에 $c_3, c_2, c_1$ 을 뒤에 넣으면 $c_1c_2c_3c_3c_2c_1c_3c_2c_1...$ 로 만들 수 있다
  • 앞에 부분은 tandem repeat 으로 빼놓고 뒷부분은 원래 문자열의 앞부분을 reverse 한것과 같다.
  • 이 작업으로 문자열 뒷부분이 원래 문자열을 정렬한 상태로 두면 그 문자열은 순서대로 각 문자의 개수만큼 tandem repeat 을 이룬다
    • $c_1c_1c_2c_2c_2c_2c_3c_3...$

코드

  • 시간복잡도: $O(N^2)$
    • 정렬하는데 각 원소마다 reverse 2번: $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> a(N);
        map<int, int> cnt;
        for (auto& e: a) {
            cin >> e;
            ++cnt[e];
        }
        bool no = false;
        for (auto e: cnt) {
            if (e.second & 1) {
                no = true;
                break;
            }
        }

        if (no) {
            cout << "-1\n";
            continue;
        }

        vector<long long> sortedA(a);
        sort(all(sortedA));

        int start = 0;
        vector<pair<int, int> > operation;
        vector<int> t;

        auto swapWithFirst = [&](int i) {
            if (i == 0) return;
            for (int j = 0; j <= i; ++j) {
                operation.push_back({start + j + i + 1, a[j]});
            }
            reverse(a.begin(), a.begin() + i + 1);
            t.push_back(i + 1 << 1);
            start += i + 1 << 1;
        };
        for (int i = N - 1; i > 0; --i) {
            if (a[i] != sortedA[i]) {
                auto it = find(a.begin(), a.begin() + i, sortedA[i]);
                if (it != a.begin()) {
                    swapWithFirst(it - a.begin());
                }
                swapWithFirst(i);
            }
        }

        for (auto e: cnt) {
            t.push_back(e.second);
        }

        cout << operation.size() << '\n';
        for (auto [p, c]: operation) {
            cout << p << ' ' << c << '\n';
        }
        cout << t.size() << '\n';
        for (auto e: t) {
            cout << e << ' ';
        }
        cout << '\n';

    }
}

 

E. Anonymity Is Important

더보기

풀이

  • 병자 후보를 set 으로, 0 l r 1 쿼리를 세그먼트 트리로 관리
  • t = 0 
    • x = 0
      • set 에서 l 부터 r 까지 범위에 있는것들 다 지움 ($O(NlogN)$)
    • x = 1
      • l 노드 값 min(t[N + l], r) 로 업데이트
  • t = 1
    • 병자 후보에 없으면 병 안걸림
    • 병자 후보 set 에서의 j 의 위치 앞, 뒤에 있는 후보를 l, r 이라고 하면
    • l + 1, j 구간의 오른쪽 구간 최소값이 뒤 후보값인 r 보다 작으면 그 구간에 j가 1을 결정하므로 병자임을 확정할 수 있다. 그 외 경우엔 여러 원소가 있으므로 결정할 수 없다.
예제 그림
예제 그림

코드

  • 시간복잡도: $O(NlogN + QlogN)$
#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, Q;
    cin >> N >> Q;
    
    set<int> can;
    for (int i = 0; i < N; ++i) can.insert(i);
    vector<int> t(2 * N, 1e9);
    auto update = [&](int p, int val) {
        for (t[p += N] = val; p > 1; p >>= 1) t[p >> 1] = min(t[p], t[p ^ 1]);
    };
    auto query = [&](int l, int r) {
        int ret = 1e9;
        for (l += N, r += N; l < r; l >>= 1, r >>= 1) {
            if (l & 1) ret = min(ret, t[l++]);
            if (r & 1) ret = min(ret, t[--r]);
        }
        return ret;
    };

    while (Q--) {
        int t2, l, r, x, j;
        cin >> t2;
        if (t2 == 0) {
            cin >> l >> r >> x; --l; --r;
            if (x == 0) {
                for (auto it = can.lower_bound(l); it != can.end() && r >= *it;) {
                    can.erase(it);
                    it = can.lower_bound(l);
                }
            } else {
                update(l, min(t[l + N], r));
            }
        } else {
            cin >> j; --j;
            if (!can.count(j) || !can.size()) {
                cout << "NO\n";
                continue;
            }

            int l = 0, r = N;
            auto it = can.lower_bound(j);
            if (it != can.begin()) l = *prev(it) + 1;
            if (next(it) != can.end()) r = *next(it);

            cout << (query(l, N) < r ? "YES\n" : "N/A\n");
        }
    }
}
728x90

문제링크

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

 

1420번: 학교 가지마!

첫째 줄에 도시의 세로 크기 N과 가로 크기 M이 주어진다. (1 ≤ N, M ≤ 100) 둘째 줄부터 N개의 줄에 도시의 모양이 주어진다. 비어있으면 점('.'), 벽은 '#', 도현이의 위치는 K, 학교의 위치는 H이다.

www.acmicpc.net

풀이

  • K, H 를 두 부분으로 나누는 Minimum cut 구하기 = Maximum flow
  • K, H 가 인접해서 있는 경우 불가능
  • 벽으로 바꿀 칸은 한번만 flow 경로에 포함되어야 하므로 정점분할

정점 모델링 이미지
정점 모델링

코드

  • 각 칸 정점번호: row * M + col
  • 정점번호 u 의
    • in = 2 * u
    • out = 2 * u + 1
#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(int to_, int c_) {
        to = to_;
        c = c_;
        f = 0;
        reverse = nullptr;
    }

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

int dr[4] = {0, 0, 1, -1};
int dc[4] = {1, -1, 0, 0};

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

    int N, M;
    cin >> N >> M;
    vector<string> a(N);
    for (auto& e: a) {
        cin >> e;
    }

    vector<vector<Edge*> > adj(2 * N * M);
    auto makeEdge = [&](int u, int v) {
        auto e1 = new Edge(v, 1);
        auto e2 = new Edge(u, 0);
        e1 -> reverse = e2;
        e2 -> reverse = e1;
        adj[u].push_back(e1);
        adj[v].push_back(e2);
    };

    int S, T;
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            if (a[i][j] == '#') continue;

            if (a[i][j] == 'K') {
                S = 2 * (i * M + j) + 1;
            } else if (a[i][j] == 'H') {
                T = 2 * (i * M + j);
            }

            for (int dir = 0; dir < 4; ++dir) {
                int ni = i + dr[dir];
                int nj = j + dc[dir];
                if (ni < 0 || ni >= N || nj < 0 || nj >= M) continue;
                if (a[ni][nj] == '#') continue;
                makeEdge(2 * (i * M + j) + 1, 2 * (ni * M + nj));
            }
        }
    }
    for (int i = 0; i < N * M; ++i) {
        makeEdge(2 * i, 2 * i + 1);
    }

    if (abs(S / 2 / M - T / 2 / M) + abs(S / 2 % M - T / 2 % M) == 1) {
        cout << "-1\n";
        return 0;
    }

    int answer = 0;
    while (true) {
        vector<Edge*> prev(2 * N * M, 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;

                prev[e -> to] = e;
                q.push(e -> to);
            }
        }

        if (!prev[T]) break;

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

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

백준 16978번: 수열과 쿼리 22  (0) 2022.03.02
백준 13548번: 수열과 쿼리 6  (0) 2022.02.28
백준 10254번: 고속도로  (0) 2022.02.26
백준 13547번: 수열과 쿼리 5  (0) 2022.02.25
백준 10266번: 시계 사진들  (0) 2022.02.23

문제링크

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

 

10254번: 고속도로

n개의 도시를 가진 나라가 있다. 이 나라에서는 도시들 중 가장 먼 두 도시 사이에 직행 고속도로를 놓으려 한다. 고속도로는 시작점과 끝점이 아닌 다른 나라를 통과해도 된다. 즉, n개의 도시

www.acmicpc.net

풀이

  • 가장 먼 점 두개는 convex hull 을 이루는 점이다.
  • rotating calipers 테크닉으로 가장 먼 점이 될 수 있는 후보를 $O(N)$ 에 구한다
    1. 초기 캘리퍼스 벡터 =  y 축, 초기 두점 = 가장 왼쪽점(pl)과 가장 오른쪽점(pr)
    2. 볼록 껍질을 회전시킴
    3. 캘리퍼스와 다음으로 만나는 점 중 먼저 바뀌는 점은 직선 pl pl + 1, 과 직선 pr pr + 1 중 캘리퍼스와 각이 더 작은 직선의 점
      1. 벡터 외적으로 구함
    4. 위 과정을 초기 두점 나올때까지 하는데 최대 $O(N)$ 번

코드

  • 시간복잡도: $O(NlogN)$
    • (convex hull)
#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);

    auto ccw = [&](pair<long long , long long >& p1, pair<long long , long long >& p2, pair<long long , long long >& p3) {
        return (p2.first - p1.first) * (p3.second - p2.second) - (p2.second - p1.second) * (p3.first - p2.first);
    };
    auto distSqr = [&](pair<long long , long long >& p1, pair<long long , long long >& p2) {
        return (p2.first - p1.first) * (p2.first - p1.first) + (p2.second - p1.second) * (p2.second - p1.second);
    };
    auto buildConvexHull = [&](vector<pair<long long , long long > >& p) {

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

        auto cmp = [&](pair<long long , long long >& p1, pair<long long , long long >& p2) {
            auto ccw_ = ccw(base, p1, p2);
            if (ccw_ == 0) {
                return distSqr(base, p1) < distSqr(base, p2); 
            }
            return ccw_ > 0;
        };
        sort(all(p), cmp);
        stack<pair<long long , long long > > st;
        st.push(p[0]);
        st.push(p[1]);
        for (int i = 2; i < p.size(); ++i) {
            auto p2 = st.top(); st.pop();
            auto p1 = st.top();
            auto p3 = p[i];
            auto ccw_ = ccw(p1, p2, p3);
            while (ccw_ < 0) {
                p2 = p1;
                st.pop(); p1 = st.top();
                ccw_ = ccw(p1, p2, p3);
            }

            if (ccw_ > 0) {
                st.push(p2);
                st.push(p3);
            } else {
                st.push(p3);
            }
        }
        vector<pair<long long , long long > > convexHull(st.size());
        while (st.size()) {
            convexHull[st.size() - 1] = st.top();
            st.pop();
        }

        return convexHull;
    };

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

        vector<pair<long long, long long> > v(N);
        for (auto& e: v) {
            cin >> e.first >> e.second;
        }

        auto ch = buildConvexHull(v);
        auto pl = min_element(all(ch)) - ch.begin();
        auto pr = max_element(all(ch)) - ch.begin();

        pair<int, int> answer = {pl, pr};
        long long tmp = distSqr(ch[pl], ch[pr]);
        int chSize = ch.size();
        for (int i = 0; i < chSize; ++i) {
            pair<long long, long long> v1 = {ch[(pl + 1) % chSize].first - ch[pl].first, ch[(pl + 1) % chSize].second - ch[pl].second};
            pair<long long, long long> v2 = {ch[pr].first - ch[(pr + 1) % chSize].first, ch[pr].second - ch[(pr + 1) % chSize].second};
            if (v1.first * v2.second - v1.second * v2.first > 0) {
                pl = (pl + 1) % chSize;
            } else {
                pr = (pr + 1) % chSize;
            }

            if (tmp < distSqr(ch[pl], ch[pr])) {
                tmp = distSqr(ch[pl], ch[pr]);
                answer = {pl, pr};
            }
        }

        cout << ch[answer.first].first << ' ' << ch[answer.first].second << ' ';
        cout << ch[answer.second].first << ' ' << ch[answer.second].second << '\n';
    }
}
728x90

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

백준 13548번: 수열과 쿼리 6  (0) 2022.02.28
백준 1420번: 학교 가지마!  (0) 2022.02.26
백준 13547번: 수열과 쿼리 5  (0) 2022.02.25
백준 10266번: 시계 사진들  (0) 2022.02.23
백준 11408번: 열혈강호 5  (0) 2022.02.22

문제링크

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

 

13547번: 수열과 쿼리 5

길이가 N인 수열 A1, A2, ..., AN이 주어진다. 이때, 다음 쿼리를 수행하는 프로그램을 작성하시오. i j: Ai, Ai+1, ..., Aj에 존재하는 서로 다른 수의 개수를 출력한다.

www.acmicpc.net

풀이

  • 업데이트 쿼리가 없으므로 쿼리 처리 순서를 속도면에서 유리하게 바꿔서 푼다
  • 원소값에 대한 cnt 배열 관리
    • 구간 집합에 원소가 추가되고 추가되면서 원소 cnt 가 1 이면 종류 증가
    • 구간 집합에 원소가 제거되고 제거되면서 원소 cnt 가 0 이면 종류 감소
  • Mo's algorithm 으로 쿼리를 정렬하여 이전 쿼리 결과 재사용률 높임

코드

  • 시간복잡도: $O((N + M)\sqrt{N}T)$
    • $T:$ 원소 추가 제거하는데 걸리는 시간 (이 문제에서는 $O(1)$)
#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);
    for (auto& e: a) {
        cin >> e;
    }
    
    int M;
    cin >> M;
    vector<tuple<int, int, int> > query(M);
    for (int i = 0; i < M; ++i) {
        int l, r;
        cin >> l >> r;
        query[i] = {l - 1, r - 1, i};
    }

    int sqrtN = sqrt(N);
    auto cmp = [&](tuple<int, int, int> t1, tuple<int, int, int> t2) {
        return get<0>(t1) / sqrtN < get<0>(t2) / sqrtN || (get<0>(t1) / sqrtN == get<0>(t2) / sqrtN && get<1>(t1) < get<1>(t2));
    };
    sort(all(query), cmp);

    vector<int> answer(M);
    vector<int> cnt(1e6 + 1, 0);
    int l = 1;
    int r = 0;
    int tmp = 0;
    for (auto [i, j, ai]: query) {
        while (i < l) tmp += ++cnt[a[--l]] == 1;
        while (i > l) tmp -= --cnt[a[l++]] == 0;
        while (j < r) tmp -= --cnt[a[r--]] == 0;
        while (j > r) tmp += ++cnt[a[++r]] == 1;
        answer[ai] = tmp;
    }

    for (auto e: answer) {
        cout << e << '\n';
    }
}

 

728x90

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

백준 1420번: 학교 가지마!  (0) 2022.02.26
백준 10254번: 고속도로  (0) 2022.02.26
백준 10266번: 시계 사진들  (0) 2022.02.23
백준 11408번: 열혈강호 5  (0) 2022.02.22
백준 9248번: Suffix Array  (0) 2022.02.21

+ Recent posts