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 가 최대이다.
증명
- b1...bk 중 0 이 있을 때
- 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';
}
}
'PS > Codeforces' 카테고리의 다른 글
[코드포스] Codeforces Round #774 (Div. 2) (코포 774 딥2) 풀이 (0) | 2022.03.19 |
---|---|
[코드포스] Codeforces Round #773 (Div. 2) (코포 773 딥2) 풀이 (0) | 2022.02.27 |
[코드포스] Educational Codeforces Round 123 (Rated for Div. 2) (에듀코포 123 딥2) 풀이 (0) | 2022.02.24 |
[코드포스] Codeforces Round #772 (Div. 2) 풀이 (0) | 2022.02.22 |
[코드포스] Codeforces Round #771 (Div. 2) 풀이 (0) | 2022.02.22 |