Codeforces Round #753 (Div. 3) A부터 D까지 업솔빙
이번 대회에는 DIV. 3답게 C번까지 풀었지만 D번은 못풀었는데, 내가 마지막에 제출한 틀린 코드에서 pair에 정렬 순서만 바꾸면 풀리는 문제라서 이제는 D번을 풀 수 있는 단계까지 눈앞에 이르렀다. E번 문제는 빡 구현문제인데 원래라면 업솔빙 했어야 하지만 codefore와 atcoder에서 내가 당장 배워야 하는 것은 dp, greedy, constructive, math, implementation, number theory 이기 때문에 pass했다. 이번 대회에서 배운 것은
- 규칙을 찾는 문제에서는 문제가 하라는 대로 일단 처음 10개항은 써보기
- 잘 모르겠어도 끝까지 포기하지 말기
- 접근법이 잘못된 것 같으면 과감히 방향을 틀기
A. Linear Keyboard (*800)
접기/펼치기
문제 설명
26개 키로 구성되어있는 키보드가 주어진다. 키는 한줄에 특정한 순서로 일렬로 늘여있고 각 키는 모두 서로 다른 알파벳 소문자로 이루어져 있다. 우리는 이 키보드로 단어
이 단어를 치기 위해서는 각각의 문자를 하나씩 순서대로 입력해야 한다. 각 문자를 입력하기 위해서는 그 문자의 정확한 위치로 손을 움직이고 눌러야 한다.
키 사이를 움직이는 것은 이 키들 사이에 있는 위치 차이의 절대값만큼 시간이 걸린다. 단어의 첫번째 문자를 입력할 때는 시간이 걸리지 않는다.
단어
문제 해설
문제에서 주어진 키의 위치를 찾아내서 각 키 사이의 절댓값을 출력하면 되는 문제이다. 이 문제에서 핵심은 주어진 키의 위치를 찾는 것이다. 문제에서는 std::find를 사용해서 찾으라고 하는데, 다른 사람의 코드를 보니 결국 소문자 a부터 z는 아스키코드 128안에 다 들어가기 때문에 배열을 128개 선언해서 문자 자체를 index로 하는 위치 배열을 만들어서 푸는 사람이 있었고 이 사람의 방식이 좋은것 같아서 공부한다.
정답 코드
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int alpha[128];
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin >> t;
while(t--){
string s; cin >> s;
for(int i = 0; i < s.size(); i++) alpha[s[i]] = i;
string a; cin >> a;
int ans = 0;
for(int i = 0; i < a.size() - 1; i++) ans += abs(alpha[a[i + 1]] - alpha[a[i]]);
cout << ans << "\n";
}
return 0;
}
B. Odd Grasshopper (*900)
접기/펼치기
문제 설명
메뚜기는 수직선 좌표
메뚜기는 점프를 하는데 현재 위치해있는 좌표의 홀/짝에 의해서 방향이 결정된다. 만약 현재 메뚜기가 위치한 좌표가 홀수라면 오른쪽으로 점프하고 현재 위치한 좌표가 짝수라면 왼쪽으로 점프한다.
이 메뚜기는 정확히
메뚜기가 정확히
문제 해설
문제에서 주어지는 제약이
규칙을 찾기 위해서 가장 쉬운 방법은 바로 나열하기이다. 처음 위치를 0이라고 하면 첫 4분동안 점프를 하면 메뚜기의 위치는
주어진 횟수
정답 코드
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin >> t;
while(t--){
long long x0, n; cin >> x0 >> n;
for(long long i = (n / 4) * 4 + 1; i <= n; i++) x0 += (x0 & 1 ? i : -i);
cout << x0 << "\n";
}
return 0;
}
C. Minimum Extraction (*1000)
접기/펼치기
문제 설명
- 배열에서 가장 작은 숫자
을 선택한다. 만약 가장 작은 숫자가 여러개 있다면 아무거나 선택한다. - 배열에서
을 제거하고, 남은 모든 원소에 을 뺀다.
따라서 각 연산을 계속 하면 배열의 길이는 결국
우리가 찾아야 할 것은 minimum extraction 연산을 계속 하면서 나오는 숫자
문제 해설
이 문제도 규칙을 찾으면 쉽게 풀 수 있다. 규칙을 찾으려면 문제에서 말하는 minimum extraction 연산을 직접 수행해 봐야한다.
배열
- 첫번째 연산을 해보자. 가장 작은 수는
이고 뺀 결과 배열은 이다. - 두번째 연산을 해보자. 가장 작은 수는
이고 뺀 결과 배열은 이다. - 세번째 연산을 해보자. 가장 작은 수는
이다. 여기서 부터 뭔가 느낌이 이상하다. 뺀 결과 배열은 이고 이 값은 이다.
즉 그냥 최솟값
정답 코드
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin >> t;
while(t--){
int n; cin >> n;
int a[n];
for(auto& x : a) cin >> x;
sort(a, a + n);
int ans = a[0];
for(int i = 1; i < n; i++) ans = max(ans, a[i] - a[i - 1]);
cout << ans << "\n";
}
return 0;
}
D. Blue-Red Permutation (*1300)
접기/펼치기
문제 설명
길이가
배열의 각 원소는 파란색 혹은 빨간색으로 칠해져 있다. 배열에 색깔이 칠해져 있지 않은 원소는 없다. 아래에 있는 두 연산 중 하나의 연산을 각 단계마다 사용할 수 있다.
- 아무 파란색으로 색칠된 원소를 선택해서 값을
내린다. - 아무 빨간색으로 색칠된 원소를 선택해서 값을
올린다.
만약 한 원소가 모두 빨간색, 혹은 모두 파란색으로 색칠되어 있다면 나머지 한 연산은 사용할 수 없을 것이다.
우리는 위에 있는 연산을 0번 혹은 그 이상 수행해서 배열의 결과 값이
문제 해설
문제에서 요구하는 정해와 거의 일치하지만 pair vector의 정렬 순서 차이가 문제의 AC, REJECT 여부를 만든 것 같다.
이 문제에서 핵심은 파란색과 빨간색으로 색칠된 원소의 특징을 알아내야 하는 것이다. 파란색으로 색칠된 원소는 그 값을 넘어서는 절대 만들 수 없다. 반대로 빨간색으로 색칠된 원소는 그 값보다 작은 값으로는 절대 될 수 없다. 만약에 우리가 이 배열을 색깔값과 원소값을 한번에 묶어서 정렬을 한다면 원소 값이 오름차순으로 배열될 것이다.
파란색으로 색칠된 값은 그 값보다 작은 수를 모두 만들 수 있기 때문에 오름차순 중에서 앞에 배치하면 더 많이 사용할 수 있을 것이다. 반대로 빨간색으로 색칠된 값은 그 값보다 큰 수를 모두 만들 수 있기 때문에 오름차순 중에서 뒤에 배치하면 더 많이 사용할 수 있을 것이다. 즉 작은 값이 만들어 질수 있는 파란색 원소를 앞에 배치하고 그 원소중에서 오름차순으로 배치한다면 차례대로 그 값이
만약
나는 처음 문제를 풀때 원소값을 우선 순위로 정렬을 했더니 빨간색, 파란색이 모두 섞여버려서 문제를 못풀었다. 진짜 조금만 남은 것 같다. 뉴비 탈출!!
정답 코드
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t; cin >> t;
while(t--){
int n; cin >> n;
int a[n];
for(auto& x : a) cin >> x;
vector<pair<char, int>> v;
for(int i = 0; i < n; i++){
char c; cin >> c;
v.push_back({c, a[i]});
}
sort(v.begin(), v.end());
bool flag = true;
for(int i = 0; i < n; i++){
if(v[i].first == 'B' && v[i].second < i + 1) flag = false;
if(v[i].first == 'R' && v[i].second > i + 1) flag = false;
}
cout << (flag ? "yes" : "no") << "\n";
}
return 0;
}
'알고리즘 > codeforces' 카테고리의 다른 글
Educational Codeforces Round 117 A부터 D까지 업솔빙 (0) | 2022.01.16 |
---|---|
Codeforces Round #754 (Div. 2) A부터 C까지 업솔빙 (0) | 2022.01.11 |
Codeforces Round #752 (Div. 2) A부터 D까지 업솔빙 (0) | 2022.01.02 |
Codeforces Round #737 (Div. 2) A부터 C까지 업솔빙 (0) | 2021.12.30 |
Educational Codeforces Round 112-C. Coin Rows (0) | 2021.12.25 |