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

+ Recent posts